code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.Consumables.SuccubisDream;
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;

	public class ArchitectJeremiah extends Monster
	{

		public function ArchitectJeremiah()
		{
			this.a = "";
			this.short = "Architect Jeremiah";
			this.imageName = "archJeremiah";
			this.long = "";

			initStrTouSpeInte(40, 150, 50, 140);
			initLibSensCor(60, 60, 0);

			this.lustVuln = 0;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 4000;
			this.weaponName = "nothing";
			this.weaponVerb = "bash";
			this.weaponAttack = 0;
			this.armorName = "cracked stone";
			this.armorDef = 100;
			this.lust = 30;
			this.bonusLust = 20;
			this.additionalXP = 1000;
			this.gems = 250 + rand(250);
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			checkMonster();
		}

		override protected function handleFear():Boolean{
			return true;
		}

		override protected function outputDefaultTeaseReaction(lustDelta:Number):void{
			if (lustDelta == 0) outputText("\n\n" + capitalA + short + " doesn't seem to be affected in any way.");
			outputText("\n\n[say: Oh, you, trying to tease me into submission. Thank you for the display, but no.]");
			if (this.lust >= this.maxLust()) this.lust = 0;
		}

		public function rebuild():void{
			var options:Array = [
			"[say: How rude. First, the demons destroyed our chastity. Now, our manners.]",
			"[say: Vilkus will be done soon. You can tell him to punish you then. He will be very thorough.]",
			"[say: Ah, pain. It is a good way to remember your humanity! You are hurting me, right?]",
			"[say: Have I shown you my statues? I really like them. It's like living forever! Or dying forever. Common mistake.]"];
			if (player.demonScore() > 3) options.push("[say: Are you a demon? Vilkus said we'd eradicate them all. Ah! You are here to be eradicated! Makes sense.]");
			if (game.combat.damageType == game.combat.DAMAGE_MAGICAL_MELEE || game.combat.damageType == game.combat.DAMAGE_MAGICAL_RANGED) options.push("[say: A fellow wizard! You're here to learn about my statues, right? Well, there's much to talk about. Arcane runes, alchemical ingredients, the right phase of the moon, the- Ah, hello there!]");
			if (player.isNaga() && player.nagaScore() > 2 && player.gender > 1) options.push("[say: Oh my. I've always loved nagas. Good thing I can't feel anything, otherwise I'd be breaking several oaths right now.]");
			armorDef = 100;
			outputText(options[rand(options.length)]);
			outputText("\nJeremiah glows and pulses with magical energy while smirking, causing the marble fragments in the room to hasten their reforming.");
			for each(var monster:Monster in game.monsterArray){
				if (monster is IncubusStatue || monster is SuccubusStatue || monster is ImpStatue){
					monster.addHP(100);
					outputText("\n" + monster.capitalA + monster.short + " is healed! (" + Math.round(100) + ")");
				}
			}
			outputText("\nJeremiah's armor restored!");
		}

		override protected function performCombatAction():void
		{
			rebuild();

		}

	}

}


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.Consumables.SuccubisDream;
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.Scenes.Areas.Bog.LizanRogue;
	import classes.Scenes.Areas.GlacialRift.Amarok;
	import classes.Scenes.Areas.GlacialRift.FrostGiant;
	import classes.Scenes.Areas.GlacialRift.Valkyrie;
	import classes.Scenes.Areas.GlacialRift.Yeti;
	import classes.Scenes.Areas.HighMountains.Basilisk;
	import classes.Scenes.Areas.HighMountains.Cockatrice;
	import classes.Scenes.Areas.HighMountains.Phoenix;
	import classes.Scenes.Areas.Swamp.CorruptedDrider;
	import classes.Scenes.Monsters.GoblinElder;
	import classes.Scenes.Monsters.ImpOverlord;
	import classes.Scenes.Quests.UrtaQuest.MinotaurLord;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;

	public class AspectOfLaurentius extends Monster
	{

		public function AspectOfLaurentius()
		{
			this.a = "";
			this.short = "Aspect of Laurentius";
			this.imageName = "aspctlaurentius";
			this.long = "";

			initStrTouSpeInte(90, 0, 75, 200);
			initLibSensCor(60, 60, 50);

			this.lustVuln = 1;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 35;
			this.bonusHP = 3200;
			this.weaponName = "nothing";
			this.weaponVerb = "bash";
			this.weaponAttack = 0;
			this.armorName = "ethereal robes";
			this.armorDef = 0;
			this.lust = 30;
			this.bonusLust = 20;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.PhysicalResistance, 0.6, 0, 0, 0);
			this.createPerk(PerkLib.Immovable);
			this.additionalXP = 3200;
			this.gems = 2500;
			checkMonster();
			prevHP = maxHP();
		}
		public var prevHP:Number;

		override public function react(context:int):Boolean{
			if (context == CON_AFTERDAMAGED && HP > 0){
				game.output.text("\n[say: How trifling. Persuading Reality that I am weaker than you... you will need a stronger argument.]");
				var healed:Number = Math.round((prevHP - HP) * 0.6);
				addHP(healed);
				game.output.text("(" + healed + ")");
				prevHP = HP;
			}
			return true;
		}

		override protected function outputDefaultTeaseReaction(lustDelta:Number):void{
			if (lustDelta == 0) outputText("\n\n" + capitalA + short + " doesn't seem to be affected in any way.");
			outputText("\n\n" + capitalA + short + " shows desire, but you doubt he'll give up on fighting by sheer lust.");
		}

		override protected function handleStun():Boolean{
			if ((game.combat.combatRound % 4 == 0 && game.combat.combatRound != 0) || (statusEffectv1(StatusEffects.Apotheosis) >= 1 && summonedTurn == 0)) return true;
			else
			{
				return super.handleStun();
			}
		}

		override protected function handleFear():Boolean{
			outputText("[say: There is nothing in this world that frightens me, [name]. Strengthen your mind, do not attempt to weaken mine.]");
			return true;
		}

		public function apotheosis():void{
			switch(game.combat.combatRound){
				case 4:
					outputText("[say: Yes, you are strong! In my travels, I have witnessed many like you. Diamonds in the rough, ready to be refined, to accept the light of Divinity. Embrace it!]");
					break;
				case 12:
					outputText("[say: Show me your power, wizard! Unleash your true potential! Conquer reality, overpower it!]");
					break;
				case 20:
					outputText("[say: Do you see? The power that your will exerts over the material plane. It is your duty to reshape it, remake it to your will!]");
					break;
				default:
					outputText("[say: Yes! This energy, this flame! These are the building blocks of a new world! This is what the wheel of Time and Space turns upon!]");
					break;
			}
			outputText("\nThe ethereal entity glows brightly, releasing a pulse of arcane energy!");
			outputText("\nThe spell hits you, and instead of being damaged or hurt, you feel enlightened; more connected to the Aether, mind expanding with magical knowledge!");
			outputText("\nDoubled Spell Power!");
			outputText("\nLaurentius' spell power doubled!");
			if (!player.hasStatusEffect(StatusEffects.Apotheosis)){
				player.createStatusEffect(StatusEffects.Apotheosis,1,0,0,0);
				createStatusEffect(StatusEffects.Apotheosis,1,0,0,0);
			}else{
				player.addStatusValue(StatusEffects.Apotheosis, 1, 1);
				addStatusValue(StatusEffects.Apotheosis, 1, 1);
			}
		}

		public function whitefire():void{
			var options:Array = [
			"[say: The flesh is a trap. No paths lead hence.]",
			"[say: This world burns. We can build one that endures.]",
			"[say: They sought to return to their world. I sought to make a new, better one.]",
			"[say: Survive. Show me that the fire that burns inside you is stronger than the one around you.]"];
			outputText(options[rand(options.length)]);
			outputText("\nThe ethereal being waves a hand in the air. The ground under your feet wobbles, and, suddenly, a massive pillar of blue fire and lightning bursts forth!");
			if (!combatAvoidDamage({doDodge:true,doParry:false,doBlock:false,toHitChance:player.standardDodgeFunc(this,30)}).failed){
				outputText("\nYou manage to jump out of the way in time!");
			}else{
				outputText("\nYou fail to dodge in time, and are scorched by the all-burning magical flames!");
				game.combat.monsterDamageType = game.combat.DAMAGE_FIRE;
				player.takeDamage((100 + rand(50)) * Math.pow(2, statusEffectv1(StatusEffects.Apotheosis)), true);
			}
		}

		public var summonedTurn:Number = 0;
		public function summonFodder():void{
			if (game.monsterArray.length > 1) game.monsterArray.length = 1;
			outputText("\nThe ethereal sorcerer weaves a powerful spell, creating a glowing cyan ball in his hands. He throws it downwards, and it explodes in a mighty flash!");
			outputText("\nThe ball expands, and from it three new enemies appear!");
			outputText("\n[say: Behold, Champion. Our souls are a forge, and through it we can reshape worlds. Test the limits of your newfound might, exert your will over lesser beings.]");
			var possiblechoices:Array = [new Amarok, new ImpOverlord, new GoblinElder, new Phoenix, new Valkyrie, new Basilisk, new LizanRogue];
			for (var i:int = 0 ; i < 3; i++){
				var choice:int = rand(possiblechoices.length);
				possiblechoices[choice].short = "ethereal " + possiblechoices[choice].short;
				outputText("\nA new " + possiblechoices[choice].short + " has appeared!");
				game.monsterArray.push(possiblechoices[choice]);
				possiblechoices.splice(choice, 1);
			}
			game.monsterArray[1].tookAction = true;
			game.monsterArray[2].tookAction = true;
			game.monsterArray[3].tookAction = true;
			outputText("\nLaurentius steps back and watches, surrounding himself in an impenetrable shield.");
			createPerk(PerkLib.Invincible, 0, 0, 0, 0);
			createPerk(PerkLib.Resolute, 0, 0, 0, 0);
			summonedTurn = game.combat.combatRound;
		}

		override protected function performCombatAction():void
		{
			if (game.monsterArray.length > 1 && summonedTurn + 3 == game.combat.combatRound){
				outputText("Laurentius steps forward once again. With a wave of his hand, all the summoned enemies vanish, turning into glowing blue dust and flowing towards the wizard. He returns to the fight!");
				outputText("Laurentius is no longer invincible!");
				for (var i:int = 1; i < game.monsterArray.length; i++){
					if (game.monsterArray[i].HP <= 0){
						outputText("\nLaurentius is hurt from absorbing a defeated creature.");
						HP -= 100;
						outputText("(" + 100 + ")");
					}
				}
				removePerk(PerkLib.Invincible);
				removePerk(PerkLib.Resolute);
                game.combat.removeMonster(1,3);
				return;
			}
			if (hasPerk(PerkLib.Invincible)){
				outputText("Laurentius watches.");
				return;
			}
			prevHP = HP;
			if ((game.combat.combatRound) % 4 == 0 && game.combat.combatRound != 0){
				apotheosis();
				return;
			}
			if (statusEffectv1(StatusEffects.Apotheosis) >= 1 && (game.combat.combatRound + 3) % 8 == 0 && game.combat.combatRound > 0){
				summonFodder();
				return;
			}
			whitefire();

		}

	}

}

license: unknown


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;

	public class ImpStatue extends Monster
	{

		public function ImpStatue()
		{
			this.a = "";
			this.short = "Imp Statue";
			this.imageName = "incStatue";
			this.long = "";

			initStrTouSpeInte(40, 50, 80, 50);
			initLibSensCor(60, 60, 0);

			this.lustVuln = 0.9;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 400;
			this.weaponName = "nothing";
			this.weaponVerb = "spell casting";
			this.weaponAttack = 20;
			this.armorName = "cracked stone";
			this.armorDef = 70;
			this.lust = 30;
			this.bonusLust = 75;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.Resolute, 0, 0, 0, 0);
			checkMonster();
		}

		override protected function handleFear():Boolean{
			return true;
		}

		public function rebuilding():void{
			outputText("Pieces of the Imp Statue move together, the golem slowly reforming itself.");
		}

		public function debilitate():void{
			outputText("Fully reformed, the Imp Statue jumps and skips while weaving some type of spell.");
			outputText("\n[say: The small one amuses me. Always moving so merrily. Always casting such powerful magic.] The Imp Statue throws both hands in your direction, casting an invisible spell on you!\n");
			var container:Object = {doDodge:true, doParry:true, doBlock:false, doFatigue:false};
			if (!playerAvoidDamage(container)){
				if (player.shield == game.shields.DRGNSHL && rand(3) == 0) outputText("\n\nYou're hit by the spell, but thankfully manage to raise your shield in time. The black magic is absorbed and nullified!");
				else{
					outputText("\nYou're hit in full by the debilitating spell!");
					if (player.stun()) outputText("You're Stunned!");
					if (rand(3) != 0 && !player.hasStatusEffect(StatusEffects.Blind)){
						outputText(" You're Blinded!");
						player.createStatusEffect(StatusEffects.Blind, 3, 0, 0, 0);
					}
					if (!player.hasStatusEffect(StatusEffects.Marked)){
						outputText(" You're Hexed!");
						player.createStatusEffect(StatusEffects.Marked, 2,0,0,0);
					}
				}
			}
			outputText("\n[say: Didn't even know it could do all that, really.]");
			outputText("\nThe statue cracks into several pieces after its attack.");
			outputText("(" + (HP - maxHP()/2) + ")");
			HP = maxHP() / 2;

		}

		override protected function performCombatAction():void
		{
			for each(var monster:Monster in game.monsterArray){
				if (monster is ArchitectJeremiah){
					if (monster.HP <= 0){
						HP = 0;
						outputText("Without its master control, the Imp Statue falls apart, inert.");
						return;
					}
				}
			}
			if (lust >= maxLust()){
				outputText("The statue stops and begins vibrating. In an instant, it cracks, unable to contain its own lust.");
				outputText("(" + (HP - maxHP()/2) + ")");
				HP = maxHP() / 2;
				lust = 0;
				return;
			}
			if (HP == maxHP()) debilitate();
			else rebuilding();

		}

	}

}


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;

	public class IncubusStatue extends Monster
	{

		public function IncubusStatue()
		{
			this.a = "";
			this.short = "Incubus Statue";
			this.imageName = "incStatue";
			this.long = "";

			initStrTouSpeInte(100, 100, 50, 50);
			initLibSensCor(60, 60, 0);

			this.lustVuln = 0.65;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 600;
			this.weaponName = "scimitar";
			this.weaponVerb = "slash";
			this.weaponAttack = 70;
			this.armorName = "cracked stone";
			this.armorDef = 70;
			this.lust = 30;
			this.bonusLust = 75;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.Resolute, 0, 0, 0, 0);
			checkMonster();
		}

		override protected function handleFear():Boolean{
			return true;
		}

		public function rebuilding():void{
			outputText("Pieces of the Incubus Statue move together, the golem slowly reforming itself.");
		}

		public function omnislash():void{
			outputText("Fully reformed, the tall Incubus brandishes two scimitars. It positions itself in a combat stance, the marble and rock rumbling loudly.");
			outputText("\n[say: This is always fun, yes.] The Incubus dashes at you with incredible speed and strength!\n");
			createStatusEffect(StatusEffects.Attacks, 5,0,0,0);
			eAttack();
			outputText("\n[say: Good for more than sex, these demons!]");
			outputText("\nThe statue cracks into several pieces after its attack.");
			outputText("(" + (HP - maxHP()/2) + ")");
			HP = maxHP() / 2;
		}

		override protected function performCombatAction():void
		{
			for each(var monster:Monster in game.monsterArray){
				if (monster is ArchitectJeremiah){
					if (monster.HP <= 0){
						HP = 0;
						outputText("Without its master control, the Incubus Statue falls apart, inert.");
						return;
					}
				}
			}
			if (lust >= maxLust()){
				outputText("The statue stops and begins vibrating. In an instant, it cracks, unable to contain its own lust.");
				outputText("(" + (HP - maxHP()/2) + ")");
				HP = maxHP() / 2;
				lust = 0;
				return;
			}
			if (HP == maxHP()) omnislash();
			else rebuilding();
		}

	}

}


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;
	import classes.internals.*;

	public class SentinelOfApostasy extends Monster
	{
		public var sealedRound:int = 0;

		public function SentinelOfApostasy()
		{
			this.a = "the ";
			this.short = "Sentinel of Apostasy";
			this.imageName = "apostsent";
			this.long = "";

			initStrTouSpeInte(100, 80, 70, 50);
			initLibSensCor(30, 30, 0);

			this.lustVuln = 0.5;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 800;
			this.weaponName = "spear";
			this.weaponVerb = "stab";
			this.weaponAttack = 25;
			this.armorName = "cracked stone";
			this.armorDef = 40;
			this.lust = 10;
			this.bonusLust = 20;
			this.additionalXP = 500;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			checkMonster();
		}

		public function humanity():void{
			outputText("The armored sentinel suddenly stops attacking mid strike. It rears back and looks at its own stony hands, trembling, as if it was struck by a sudden revelation.");
			outputText("\nIt then looks at the sky with slumped shoulders, its pose abandoning any pretense of combat. It will recover soon, but something you did definitely affected it!");
			lust -= 15;
			fatigue -= 5;
		}

		override protected function outputDefaultTeaseReaction(lustDelta:Number):void{
			if (lustDelta == 0) outputText("\n\n" + capitalA + short + " doesn't seem to be affected in any way.");
			outputText("\n\n" + capitalA + short + " does not show any emotion, but you can swear your display gave it pause... if just for a moment.");
		}

		public function piercingStrike():void{//can't be parried, ignores armor.
			outputText("The armored sentinel rears back, holding its spear with both hands, and lunges forward with inhuman speed, in a piercing attack!");
			var dodgeResult:Object = combatAvoidDamage({doDodge:true,doParry:false,doBlock:true, doFatigue:true});
			if (dodgeResult.dodge != null) outputText("\nYou barely manage to dodge the powerful thrust.");
			else{
				if (dodgeResult.block) outputText("\nYou raise your shield at the last moment and manage to block the powerful thrust with great effort.");
				else{
					outputText("\nYou fail to avoid the powerful thrust, and the tip of its spear strikes true, completely piercing your armor and denying any defense!");
					player.takeDamage(100 + rand(30),true);
				}

			}
			fatigue += 10;
		}

		//seals physical moves.
		public function sealPhysical():void{
			outputText("The armored sentinel raises its spear to the sky in a devout pose, each limb locking into place with inhuman precision, small clouds of dust rising in its joints. A thin wave of light pulses outwards from the living statue, roaming unerringly towards you.");
			outputText("\nThe light hits you, its effect abstract but immediate; your muscles feel numb, your limbs leaden. <b>Your physical attacks are sealed!</b>");
			player.createStatusEffect(StatusEffects.SentinelPhysicalDisabled, 3, 0, 0, 0);
			sealedRound = game.combat.combatRound;
			fatigue += 15;
		}

		override protected function performCombatAction():void
		{
			if (rand(lust - 35) > rand(100)){
				humanity();
				return;
			}
			var actionChoices:MonsterAI = new MonsterAI();
			actionChoices.add(eAttack, 2, true, 0, FATIGUE_NONE, RANGE_MELEE);
			actionChoices.add(sealPhysical, 1, !player.hasStatusEffect(StatusEffects.SentinelPhysicalDisabled) && game.combat.combatRound + 2 >= sealedRound, 15, FATIGUE_MAGICAL, RANGE_OMNI);
			actionChoices.add(piercingStrike,(player.damagePercent(false, false, false, true) > 50 ? 2 : 1), true, 10, FATIGUE_PHYSICAL, RANGE_MELEE_CHARGING);
			actionChoices.exec();

		}

	}

}


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffectType;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;
	import classes.internals.*;

	public class SentinelOfBlasphemy extends Monster
	{
		public var sealedRound:int = 0;

		public function SentinelOfBlasphemy()
		{
			this.a = "the ";
			this.short = "Sentinel of Blasphemy";
			this.imageName = "blasphsent";
			this.long = "";

			initStrTouSpeInte(80, 80, 25, 100);
			initLibSensCor(30, 30, 0);

			this.lustVuln = 0.6;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 800;
			this.weaponName = "staff";
			this.weaponVerb = "shot";
			this.weaponAttack = 20;
			this.armorName = "cracked stone";
			this.armorDef = 30;
			this.lust = 10;
			this.bonusLust = 20;
			this.additionalXP = 500;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			checkMonster();
		}

		public function countPositiveBuffs():Number{
			var count:Number = 0;
			for each(var dispellable:StatusEffectType in StatusEffects.dispellablePositiveEffects) if (player.indexOfStatusEffect(dispellable) != -1) count++;
			return count;
		}

		public function humanity():void{
			outputText("The robed sentinel suddenly stops attacking mid casting. It rears back and looks at its own stony hands, trembling, as if it was struck by a sudden revelation.");
			outputText("\nIt then kneels, both hands together in a prayer. It will recover soon, but something you did definitely affected it!");
			lust -= 15;
			fatigue -= 5;
		}

		override protected function outputDefaultTeaseReaction(lustDelta:Number):void{
			if (lustDelta == 0) outputText("\n\n" + capitalA + short + " doesn't seem to be affected in any way.");
			outputText("\n\n" + capitalA + short + " does not show any emotion, but you can swear your display gave it pause... if just for a moment.");
		}

		public function dispel():void{
			outputText("The robed sentinel raises a hand to the sky, putting another in its chest. Its skyward hand glows with magical energy, which it then launches at you!");
			var dodgeResult:Object = combatAvoidDamage({doDodge:true,doParry:false,doBlock:false});
			if (dodgeResult.dodge != null) outputText("\n\nYou manage to dodge out of the way just in time, avoiding the magical attack.");
			else{
				if (player.shield == game.shields.DRGNSHL && rand(3) == 0) outputText("\n\nYou're hit by the attack, but thankfully manage to raise your shield in time. The spell is absorbed and nullified!");
				else{
					outputText("\n\nYou're hit by the spell! It doesn't hurt, but there's something distinctively different about you. You feel... purged. All positive buffs removed!");
					for each(var dispellable:StatusEffectType in StatusEffects.dispellablePositiveEffects) if (player.indexOfStatusEffect(dispellable) != -1) player.removeStatusEffect(dispellable);
				}

			}
			fatigue += 25;
		}

		public function sealMagical():void{
			outputText("The robed sentinel raises its staff to the sky in a devout pose, each limb locking into place with inhuman precision, small clouds of dust rising in its joints. A thin wave of light pulses outwards from the living statue, roaming unerringly towards you.");
			outputText("\nThe light hits you, its effect abstract but immediate; your voice catches in your throat, and the very concept of speech leaves your mind. Your magical attacks are sealed!");
			player.createStatusEffect(StatusEffects.SentinelOmniSilence, 3, 0, 0, 0);
			sealedRound = game.combat.combatRound;
			fatigue += 15;
		}

		override protected function performCombatAction():void
		{
			if (rand(lust - 35) > rand(100)){
				humanity();
				return;
			}
			var actionChoices:MonsterAI = new MonsterAI();
			actionChoices.add(eAttack, 2, true, 0, FATIGUE_NONE, RANGE_RANGED);
			actionChoices.add(sealMagical, 1, !player.hasStatusEffect(StatusEffects.SentinelOmniSilence) && game.combat.combatRound + 2 >= sealedRound, 15, FATIGUE_MAGICAL, RANGE_OMNI);

			var numberofPositiveEffects:Number = countPositiveBuffs();
			actionChoices.add(dispel, numberofPositiveEffects, true, 25, FATIGUE_MAGICAL, RANGE_OMNI);
			actionChoices.exec();

		}

	}

}


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;
	import classes.internals.*;

	public class SentinelOfHeresy extends Monster
	{
		public var sealedRound:int = 0;

		public function SentinelOfHeresy()
		{
			this.a = "the ";
			this.short = "Sentinel of Heresy";
			this.imageName = "heresysent";
			this.long = "";

			initStrTouSpeInte(40, 120, 60, 50);
			initLibSensCor(60, 60, 0);

			this.lustVuln = 0.7;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 1100;
			this.canBlock = true;
			this.shieldBlock = 30;
			this.shieldName = "giant stone shield";
			this.weaponName = "shield";
			this.weaponVerb = "bash";
			this.weaponAttack = 20;
			this.armorName = "cracked stone";
			this.armorDef = 70;
			this.lust = 30;
			this.bonusLust = 20;
			this.additionalXP = 500;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			checkMonster();
		}

		public function humanity():void{
			outputText("The nude sentinel suddenly stops attacking mid casting. It rears back and looks at its own stony hands, trembling, as if it was struck by a sudden revelation.");
			outputText("\nIt then kneels, crashing its shield onto the ground in defeat. It will recover soon, but something you did definitely affected it!");
			lust -= 15;
			fatigue -= 5;
		}

		override protected function outputDefaultTeaseReaction(lustDelta:Number):void{
			if (lustDelta == 0) outputText("\n\n" + capitalA + short + " doesn't seem to be affected in any way.");
			outputText("\n\n" + capitalA + short + " does not show any emotion, but you can swear your display gave it pause... if just for a moment.");
		}

		public function martyrdom():void{
			outputText("The nude sentinel covers itself in its shield, which begins shining, the emblazoned religious heraldry glowing with magical energy. A gentle wave of energy pulses outwards, heading towards his allies.");
			for each(var monster:Monster in game.monsterArray){
				if (!(monster is SentinelOfHeresy) && monster.HP > 0){
					var healed:Number = Math.round(maxHP() * (1 + rand(2))*0.1);
					monster.addHP(healed);
					outputText("\n" + monster.capitalA + monster.short + " is healed! (" + Math.round(healed) + ")");
				}
			}
			var damaged:Number = 40 + rand(40);
			outputText("\nPieces of the living statue crack and fall after casting the spell. It must be taxing on the golem's constitution.");
			HP -= damaged;
			outputText("(" + damaged + ")");
		}

		public function sealTease():void{
			outputText("The nude sentinel raises its shield to the sky in a devout pose, each limb locking into place with inhuman precision, small clouds of dust rising in its joints. A thin wave of light pulses outwards from the living statue, roaming unerringly towards you.");
			outputText("\nThe light hits you, its effect abstract but immediate; you feel ashamed and guilty of your perversions. Your tease ability is sealed!");
			player.createStatusEffect(StatusEffects.SentinelNoTease, 3, 0, 0, 0);
			sealedRound = game.combat.combatRound;
			fatigue += 15;
		}

		override protected function performCombatAction():void
		{
			if (rand(lust - 35) > rand(100)){
				humanity();
				return;
			}
			var actionChoices:MonsterAI = new MonsterAI();
			actionChoices.add(eAttack, 2, true, 0, FATIGUE_NONE, RANGE_MELEE);
			actionChoices.add(sealTease, 1, !player.hasStatusEffect(StatusEffects.SentinelNoTease) && game.combat.combatRound + 2 >= sealedRound, 15, FATIGUE_MAGICAL, RANGE_OMNI);
			for each(var monster:Monster in game.monsterArray){
				if (!(monster is SentinelOfHeresy) && monster.HP > 0 && monster.HPRatio() < .6){
					actionChoices.add(martyrdom, 2, true, 0, FATIGUE_NONE, RANGE_SELF);
					break;
				}
			}

			actionChoices.exec();

		}

	}

}


code:
package classes.Scenes.Dungeons.WizardTower
{
	import classes.Items.WeaponLib;
	import classes.Monster;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.GlobalFlags.kFLAGS;

	public class SuccubusStatue extends Monster
	{

		public function SuccubusStatue()
		{
			this.a = "";
			this.short = "Succubus Statue";
			this.imageName = "incStatue";
			this.long = "";

			initStrTouSpeInte(40, 100, 80, 100);
			initLibSensCor(60, 60, 0);

			this.lustVuln = 0.65;

			this.tallness = 6 * 12;
			this.createBreastRow(0, 1);
			initGenderless();

			this.drop = NO_DROP;
			this.ignoreLust = true;
			this.level = 22;
			this.bonusHP = 600;
			this.weaponName = "nothing";
			this.weaponVerb = "spell casting";
			this.weaponAttack = 20;
			this.armorName = "cracked stone";
			this.armorDef = 70;
			this.lust = 30;
			this.bonusLust = 75;
			this.createPerk(PerkLib.PoisonImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.BleedImmune, 0, 0, 0, 0);
			this.createPerk(PerkLib.Resolute, 0, 0, 0, 0);
			checkMonster();
		}

		override protected function handleFear():Boolean{
			return true;
		}

		public function rebuilding():void{
			outputText("Pieces of the Succubus Statue move together, the golem slowly reforming itself.");
		}

		public function lustpocalypse():void{
			outputText("Fully reformed, the Succubus Statue teases and flaunts her own body, the flawless craftsmanship of the piece creating a perfect illusion of a real, flesh and blood seductress. Your heart skips a beat as she palms her perfect breasts and nipples, her wide hips and perfect pussy...");
			outputText("\n[say: Marvelous, and so very sinful! Forbidden! FORBIDDEN!] The statue's hands glow with black magic, and, detecting your lack of focus, she launches a spell at you!\n");
			var container:Object = {doDodge:true, doParry:true, doBlock:false, doFatigue:false};
			if (!playerAvoidDamage(container)){
				if (player.shield == game.shields.DRGNSHL && rand(3) == 0) outputText("\n\nYou're hit by the spell, but thankfully manage to raise your shield in time. The black magic is absorbed and nullified!");
				else{
					outputText("\nYou're hit in full by the arousing spell, and you lose your breath over the sudden lust infusion you've received.");
					if (player.hasCock()) outputText(" Your [cock] hardens almost immediately, throbbing with need.");
					if (player.hasVagina()) outputText(" Your [vagina] swells and moistens, begging for something to fill it.");
					outputText(" Gods, you need to fuck something right now!");
					player.takeLustDamage(60 + player.lib / 10 + player.sens / 10, true);
				}
			}
			outputText("\n[say: Oh, just give up and pleasure yourself. We're all human, it's fine to do it every once in a while! Well, I'm not. Am I?]");
			outputText("\nThe statue cracks into several pieces after its attack.");
			outputText("(" + (HP - maxHP()/2) + ")");
			HP = maxHP() / 2;

		}
		override protected function performCombatAction():void
		{
			for each(var monster:Monster in game.monsterArray){
				if (monster is ArchitectJeremiah){
					if (monster.HP <= 0){
						HP = 0;
						outputText("Without its master control, the Succubus Statue falls apart, inert.");
						return;
					}
				}
			}
			if (lust >= maxLust()){
				outputText("The statue stops and begins vibrating. In an instant, it cracks, unable to contain its own lust.");
				outputText("(" + (HP - maxHP()/2) + ")");
				HP = maxHP() / 2;
				lust = 0;
				return;
			}
			if (HP == maxHP()) lustpocalypse();
			else rebuilding();

		}

	}

}


code:
/**
 * Created by aimozg on 20.02.14.
 */
package classes.Scenes.Explore
{
	import classes.BaseContent;
	import classes.Monster;
	import classes.Scenes.Areas.Bog.*;
	import classes.Scenes.Areas.Desert.*;
	import classes.Scenes.Areas.Forest.*;
	import classes.Scenes.Areas.GlacialRift.*;
	import classes.Scenes.Areas.HighMountains.*;
	import classes.Scenes.Areas.Lake.*;
	import classes.Scenes.Areas.Mountain.*;
	import classes.Scenes.Areas.Plains.*;
	import classes.Scenes.Areas.Swamp.*;
	import classes.Scenes.Areas.VolcanicCrag.*;
	import classes.Scenes.Dungeons.DeepCave.*;
	import classes.Scenes.Dungeons.DesertCave.*;
	import classes.Scenes.Dungeons.LethicesKeep.*;
	import classes.Scenes.Dungeons.Factory.*;
	import classes.Scenes.Dungeons.HelDungeon.*;
	import classes.Scenes.Monsters.*;
	import classes.Scenes.NPCs.*;
	import classes.Scenes.Places.Boat.*;
	import classes.Scenes.Places.Farm.*;
	import classes.Scenes.Places.Owca.*;
	import classes.Scenes.Places.Prison.*;
	import classes.Scenes.Quests.UrtaQuest.*;

	public class ExploreDebug extends BaseContent
	{

		public function doExploreDebug():void
		{
			clearOutput();
			menu();

			outputText("Monsters   combat each monster.\n\n");
			addButton(0, "Monsters", exploreDebugMonsters);
		}

		// array of lazy monster creators
		// 1) first go simple monsters that do not depend on/change game state
		// 2) then NPCs and quest monsters that might depend on/change game state
		// but still fightable without special initialization
		// 3) finally very special monsters, which rely on some kind of game state initialization (such as Ember)
		// and may crash or break something very heavily on attempt to fight
		private var allMonsters:Array = [
			// Generic monsters first...
			function ():Monster {return new Anemone();},
			function ():Monster {return new Basilisk();},
			function ():Monster {return new BeeGirl();},
			function ():Monster {return new ChameleonGirl();},
			function ():Monster {return new CorruptedDrider();},
			function ():Monster {return new CumWitch();},
			function ():Monster {return new DemonPack();},
			function ():Monster {return new FemaleSpiderMorph();},
			function ():Monster {return new FetishCultist();},
			function ():Monster {return new FetishZealot();},
			function ():Monster {return new FrostGiant();},
			function ():Monster {return new Ghoul();},
			function ():Monster {return new Gnoll();},
			function ():Monster {return new GnollSpearThrower();},
			function ():Monster {return new Goblin();},
			function ():Monster {return new GoblinAssassin();},
			function ():Monster {return new GooGirl();},
			function ():Monster {return new GreenSlime();},
			function ():Monster {return new Harpy();},
			function ():Monster {return new HellHound();},
			function ():Monster {return new Imp();},
			function ():Monster {return new ImpHorde("DeepCave");},
			function ():Monster {return new ImpLord();},
			function ():Monster {return new InfestedHellhound();},
			function ():Monster {return new Kitsune("black");},
			function ():Monster {return new Kitsune("blonde");},
			function ():Monster {return new Kitsune("red");},
			function ():Monster {return new MaleSpiderMorph();},
			function ():Monster {return new Minotaur(true);},
			function ():Monster {return new Minotaur(false);},
			function ():Monster {return new MinotaurMob();},
			function ():Monster {return new Naga(); },
			function ():Monster {return new RandomSuccubus();},
			function ():Monster {return new SandTrap();},
			function ():Monster {return new SandWitch();},
			function ():Monster {return new Satyr();},
			function ():Monster {return new SharkGirl();},
			function ():Monster {return new TentacleBeast();},
			function ():Monster {return new Valkyrie();},
			function ():Monster {return new WormMass();},
			function ():Monster {return new Yeti(); },
			function ():Monster {return new Ghoul(); },
			// ...NPCs, quest, and named monsters second, ...
			function ():Monster {return new Akbal();},
			function ():Monster {return new Amily();},
			function ():Monster {return new Brigid();},
			function ():Monster {return new Ceraph();},
			function ():Monster {return new GooArmor();},
			function ():Monster {return new Farmers();},
			function ():Monster {return new GoblinBroodmother();},
			function ():Monster {return new HarpyMob();},
			function ():Monster {return new HarpyQueen();},
			function ():Monster {return new Hel();},
			function ():Monster {return new IncubusMechanic();},
			function ():Monster {return new Isabella();},
			function ():Monster {return new Izma();},
			function ():Monster {return new Izumi();},
			function ():Monster {return new Jojo();},
			function ():Monster {return new Kelt();},
			function ():Monster {return new Kiha();},
			function ():Monster {return new Lethice();},
			function ():Monster {return new LustyDemons();},
			function ():Monster {return new Marble();},
			function ():Monster {return new MilkySuccubus();},
			function ():Monster {return new Minerva();},
			function ():Monster {return new MinotaurLord();},
			function ():Monster {return new OmnibusOverseer();},
			function ():Monster {return new PhoenixPlatoon();},
			function ():Monster {return new SandMother();},
			function ():Monster {return new SandWitchMob();},
			function ():Monster {return new Scruffy();},
			function ():Monster {return new SecretarialSuccubus();},
			function ():Monster {return new Shouldra();},
			function ():Monster {return new Sirius();},
			function ():Monster {return new Sophie();},
			function ():Monster {return new SpiderMorphMob();},
			function ():Monster {return new Tamani();},
			function ():Monster {return new TamanisDaughters();},
			function ():Monster {return new Vala();},
			function ():Monster {return new Zetaz();},
			function ():Monster {return new Aiko();},
			function ():Monster {return new Yamata();},
			// ...VERY special monsters third.
			function ():Monster {return new EncapsulationPod();},
			function ():Monster {return new Sheila();},
			function ():Monster {return new Holli();},
			function ():Monster {return new Helspawn();},
			function ():Monster {return new Marae();},
			function ():Monster {return new Ember();}
		];

		private function exploreDebugMonsters(monsterIdx:int = 0):void
		{
			clearOutput();
			menu();

			if (monsterIdx == 0) {
				outputText("WARNING. You are going to fight (probably) all the monsters. " +
						"You won't be penalized for defeat or awarded for victory. " +
						"Even though the monsters' victory and defeat events are removed, " +
						"fighting certain quest monsters/NPCs through this debug scene " +
						"may put their scenes into inconsistent state. \n\n");
			}

			if (monsterIdx >= allMonsters.length) {
				outputText("You have fought every monster.");
			} else {
				var m:Monster = allMonsters[monsterIdx]();
				m.onDefeated = function (hpVictory:Boolean):void
				{
					game.inCombat = false;
					game.combat.clearStatuses();
					statScreenRefresh();
					exploreDebugMonsters(monsterIdx + 1);
				};
				m.onWon = function (hpVictory:Boolean, pcCameWorms:Boolean = false):void
				{
					game.inCombat = false;
					game.combat.clearStatuses();
					statScreenRefresh();
					exploreDebugMonsters(monsterIdx + 1);
				};
				m.onPcRunAttempt = function ():void
				{
					game.inCombat = false;
					game.combat.clearStatuses();
					statScreenRefresh();
					exploreDebugMonsters(monsterIdx + 1);
				};
				outputText("You are going to fight " + m.a + " " + m.short + ".");
				addButton(0, "Fight", function():void{
					outputText("\n\nStarting combat...");
					startCombat(m);
				});
				addButton(1, "Skip", exploreDebugMonsters, monsterIdx+1);
				addButton(2, "Heal", function():void{
					player.HP = player.maxHP();
					player.lust = 0;
					statScreenRefresh();
				});
			}
			if (monsterIdx>1) addButton(6, "Go Back", exploreDebugMonsters, monsterIdx-1);
			addButton(9, "Enough", playerMenu);
		}

		public function ExploreDebug()
		{
		}
	}
}


code:
/**
 * Created by aimozg on 12.01.14.
 */
package classes.Scenes
{
	import classes.*;
	import classes.GlobalFlags.*;
	import classes.Items.*;
	import classes.internals.*;
	import coc.view.*;
	import flash.text.*;
	import mx.logging.*;

	use namespace kGAMECLASS;

	public class Inventory extends BaseContent {
		private static const LOGGER:ILogger = LoggerFactory.getLogger(Inventory);

		private static const inventorySlotName:Array = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"];

		//TODO refactor storage into own type?
		public static const STORAGE_JEWELRY_BOX:String = "Equipment Storage - Jewelry Box";

		private var itemStorage:Array;
		private var gearStorage:Array;
		private var prisonStorage:Array;
		private var callNext:Function;		//These are used so that we know what has to happen once the player finishes with an item
		private var callOnAbandon:Function;	//They simplify dealing with items that have a sub menu. Set in inventoryMenu and in takeItem
		private var currentItemSlot:ItemSlot;	//The slot previously occupied by the current item - only needed for stashes and items with a sub menu.
		public var usedItem:Boolean = false;

		public function Inventory(saveSystem:Saves) {
			itemStorage = [];
			gearStorage = [];
			prisonStorage = [];
			saveSystem.linkToInventory(itemStorageDirectGet, gearStorageDirectGet);
		}

		public function showStash():Boolean {
			return player.hasKeyItem("Equipment Rack - Weapons") || player.hasKeyItem("Equipment Rack - Armor") || player.hasKeyItem("Equipment Rack - Shields") || itemStorage.length > 0 || flags[kFLAGS.ANEMONE_KID] > 0 || player.hasKeyItem(Inventory.STORAGE_JEWELRY_BOX) || flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER] > 0;
		}

		public function itemStorageDirectGet():Array { return itemStorage; }

		public function gearStorageDirectGet():Array { return gearStorage; }

		public function prisonStorageDirectGet():Array { return prisonStorage; }

//		public function currentCallNext():Function { return callNext; }

		public function itemGoNext():void { if (callNext != null) doNext(callNext); }

		public function inventoryMenu():void {
			var x:int;
			var foundItem:Boolean = false;
			if (game.inCombat) {
				callNext = inventoryCombatHandler; //Player will return to combat after item use
			}
			else {
				spriteSelect(null);
				imageSelect(null);
				callNext = inventoryMenu; //In camp or in a dungeon player will return to inventory menu after item use
			}
			hideMenus();
			hideUpDown();
			clearOutput();
			game.displayHeader("Inventory");
			outputText("Equipment:\n");
			outputText("Weapon: " + player.weapon.name + " (Attack: " + player.weaponAttack + ")\n");
			outputText("Shield: " + player.shield.name + " (Block Rating: " + player.shieldBlock + ")\n");
			outputText("Armour: " + (player.armor.id == armors.VINARMR.id ? "Obsidian vines" : player.armor.name) + " (Defense: " + player.armorDef + ")\n");
			outputText("Upper underwear: " + player.upperGarment.name + "\n");
			outputText("Lower underwear: " + player.lowerGarment.name + "\n");
			outputText("Accessory: " + player.jewelryName + "\n");
			if (player.keyItems.length > 0) outputText("\nKey Items:\n");
			for (x = 0; x < player.keyItems.length; x++) outputText(player.keyItems[x].keyName + "\n");
			outputText("\n\n[bu: Carpentry Supplies:]");
			outputText("\n[b: Wood:] " + flags[kFLAGS.CAMP_CABIN_WOOD_RESOURCES]);
			outputText("\n[b: Nails:] " + player.keyItemv1("Carpenter's Toolbox"));
			outputText("\n[b: Stones:] " + flags[kFLAGS.CAMP_CABIN_STONE_RESOURCES]);
			menu();
			for (x = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked) {
					if (player.itemSlots[x].quantity > 0) {
						addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), useItemInInventory, x).hint(generateInventoryTooltip(player.itemSlots[x]), capitalizeFirstLetter(player.itemSlots[x].itype.longName));
						foundItem = true;
					}
					else addButtonDisabled(x, "Nothing");
				}
			}
			if (!game.inCombat) {
				addButton(10, "Unequip", manageEquipment);
			}

			if (!game.inCombat && flags[kFLAGS.DELETE_ITEMS] == 1) {
				addButton(11, "Del Item: One", deleteItems).hint("Trash your items, one by one.\n\nClick to trash all in a stack.\nClick twice to stop.", "Delete Items (Single)");
			} else if (!game.inCombat && flags[kFLAGS.DELETE_ITEMS] == 2) {
				addButton(11, "Del Item: All", deleteItems).hint("Trash all of your items in a stack.\n\nClick to stop.\nClick twice to trash your items one by one.", "Delete Items (Stack)");
			} else if (!game.inCombat && flags[kFLAGS.DELETE_ITEMS] == 0) {
				addButton(11, "Del Item: OFF", deleteItems).hint("Start throwing away your items.\n\nClick to trash your items one by one.\nClick twice to trash all in a stack.", "Delete Items (Off)");
			}

			if (!game.inCombat && inDungeon == false && inRoomedDungeon == false && flags[kFLAGS.IN_PRISON] == 0 && flags[kFLAGS.IN_INGNAM] == 0 && checkKeyItems(true)) {
				addButton(12, "Key Items", checkKeyItems);
				foundItem = true;
			}
			if (!game.inCombat && player.armor == armors.BIMBOSK) {
				addButton(13, (flags[kFLAGS.BIMBO_MINISKIRT_PROGRESS_DISABLED] == 0 ? "Disable Bimbo" : "Enable Bimbo"), game.bimboProgress.toggleProgress).hint((flags[kFLAGS.BIMBO_MINISKIRT_PROGRESS_DISABLED] == 0 ? "Disable bimbo progression from Bimbo Miniskirt." : "Enable bimbo progression from Bimbo Miniskirt."));
			}
			if (!foundItem) {
				outputText("\nYou have no usable items.");
				if (!game.inCombat) {
					removeButton(11);
				}else{
					usedItem = false;
				}
				addButton(14, "Back", exitInventory);
				return;
			}
			if (game.inCombat && player.hasStatusEffect(StatusEffects.Sealed) && player.statusEffectv1(StatusEffects.Sealed) == 3) {
				outputText("\nYou reach for your items, but you just can't get your pouches open.  Your ability to use items was sealed, and now you've wasted a chance to attack!\n\n");
				inventoryCombatHandler();
				return;
			}
			if (flags[kFLAGS.DELETE_ITEMS] > 0) outputText("\nWhich item will you discard?");
			else outputText("\nWhich item will you use?");
			outputText("\nCapacity: " + getOccupiedSlots() + " / " + getMaxSlots());
			addButton(14, "Back", exitInventory);
		}

		private function exitInventory():void {
			flags[kFLAGS.DELETE_ITEMS] = 0;
			if (game.inCombat)
				combat.combatMenu(false); //Player returns to the combat menu on cancel
			else
				playerMenu();
		}

		public function takeItem(itype:ItemType, nextAction:Function, overrideAbandon:Function = null, source:ItemSlot = null, display:Boolean = true):void {
			if (itype == null) {
				CoC_Settings.error("takeItem(null)");
				return;
			}
			if (itype == ItemType.NOTHING) return;
			if (nextAction != null)
				callNext = nextAction;
			else callNext = playerMenu;
			//Check for an existing stack with room in the inventory and return the value for it.
			var temp:int = player.roomInExistingStack(itype);
			if (temp >= 0) { //First slot go!
				player.itemSlots[temp].quantity++;
				if (display) outputText("You place " + itype.longName + " in your " + inventorySlotName[temp] + " pouch, giving you " + player.itemSlots[temp].quantity + " of them.");
				itemGoNext();
				return;
			}
			//If not done, then put it in an empty spot!
			//Throw in slot 1 if there is room
			temp = player.emptySlot();
			if (temp >= 0) {
				player.itemSlots[temp].setItemAndQty(itype, 1);
				if (source != null) player.itemSlots[temp].damage = source.damage;
				else player.itemSlots[temp].damage = 0;
				if (display) outputText("You place " + itype.longName + " in your " + inventorySlotName[temp] + " pouch.");
				itemGoNext();
				return;
			}
			if (overrideAbandon != null) //callOnAbandon only becomes important if the inventory is full
				callOnAbandon = overrideAbandon;
			else callOnAbandon = callNext;
			//OH NOES! No room! Call replacer functions!
			takeItemFull(itype, true, source);
		}

		public function returnItemToInventory(item:Useable, showNext:Boolean = true):void { //Used only by items that have a sub menu if the player cancels
			if (!debug) {
				if (currentItemSlot == null) {
					takeItem(item, callNext, callNext, null); //Give player another chance to put item in inventory
				}
				else if (currentItemSlot.quantity > 0) { //Add it back to the existing stack
					currentItemSlot.quantity++;
				}
				else { //Put it back in the slot it came from
					currentItemSlot.setItemAndQty(item, 1);
				}
			}
			if (game.inCombat) {
				inventoryCombatHandler();
				return;
			}
			if (showNext)
				doNext(callNext); //Items with sub menus should return to the inventory screen if the player decides not to use them
			else callNext(); //When putting items back in your stash we should skip to the take from stash menu
		}

		//Check to see if anything is stored
		public function hasItemsInStorage():Boolean { return itemAnyInStorage(itemStorage, 0, itemStorage.length); }

		public function countTotalFoodItems():Number { return countFoodItems(itemStorage, 0, itemStorage.length); }

		public function hasItemInStorage(itype:ItemType):Boolean { return itemTypeInStorage(itemStorage, 0, itemStorage.length, itype); }

		public function consumeItemInStorage(itype:ItemType):Boolean {
			temp = itemStorage.length;
			while(temp > 0) {
				temp--;
				if (itemStorage[temp].itype == itype && itemStorage[temp].quantity > 0) {
					itemStorage[temp].quantity--;
					return true;
				}
			}
			return false;
		}

		public function giveHumanizer():void {
			if (flags[kFLAGS.TIMES_CHEATED_COUNTER] > 0) {
				clearOutput();
				outputText("I was a cheater until I took an arrow to the knee...");
				game.gameOver();
				return;
			}
			clearOutput();
			outputText("I AM NOT A CROOK.  BUT YOU ARE!  CHEATER!\n\n");
			inventory.takeItem(consumables.HUMMUS_, playerMenu);
			flags[kFLAGS.TIMES_CHEATED_COUNTER]++;
		}

		public function getMaxSlots():int {
			var slots:int = 3;
			if (player.findPerk(PerkLib.StrongBack) >= 0) slots++;
			if (player.findPerk(PerkLib.StrongBack2) >= 0) slots++;
			slots += player.keyItemv1("Backpack");
			//Constrain slots to between 3 and 10.
			if (slots < 3) slots = 3;
			if (slots > 10) slots = 10;
			return slots;
		}
		public function unlockSlots(setMax:int = 0):void {
			var maxSlots:int = setMax || inventory.getMaxSlots();
			player.itemSlot1.unlocked = true;
			player.itemSlot2.unlocked = true;
			player.itemSlot3.unlocked = true;
			player.itemSlot4.unlocked = maxSlots >= 4;
			player.itemSlot5.unlocked = maxSlots >= 5;
			player.itemSlot6.unlocked = maxSlots >= 6;
			player.itemSlot7.unlocked = maxSlots >= 7;
			player.itemSlot8.unlocked = maxSlots >= 8;
			player.itemSlot9.unlocked = maxSlots >= 9;
			player.itemSlot10.unlocked = maxSlots >= 10;
		}
		public function getOccupiedSlots():int {
			var occupiedSlots:int = 0;
		    for (var i:int = 0; i < player.itemSlots.length; i++) {
				if (!player.itemSlot(i).isEmpty() && player.itemSlot(i).unlocked) occupiedSlots++;
			}
			return occupiedSlots;
		}
		public function emptySlots():void {
			player.itemSlot1.emptySlot();
			player.itemSlot2.emptySlot();
			player.itemSlot3.emptySlot();
			player.itemSlot4.emptySlot();
			player.itemSlot5.emptySlot();
			player.itemSlot6.emptySlot();
			player.itemSlot7.emptySlot();
			player.itemSlot8.emptySlot();
			player.itemSlot9.emptySlot();
			player.itemSlot10.emptySlot()
		}

		//Create a storage slot
		public function createStorage(number:Number = 1):Boolean {
			for (var i:Number = 0; i < number; i++){
				var newSlot:ItemSlot = new ItemSlot();
				itemStorage.push(newSlot);
			}
			return true;
		}

		public function fixStorage():int {
			var fixedStorage:int = 4;
			if (player.hasKeyItem("Camp - Chest")) fixedStorage += 6;
			if (player.hasKeyItem("Camp - Murky Chest")) fixedStorage += 4;
			if (player.hasKeyItem("Camp - Ornate Chest")) fixedStorage += 4;
			if (itemStorage.length > fixedStorage){
				itemStorage.length = fixedStorage;
			}
			else if(itemStorage.length != fixedStorage) createStorage(fixedStorage - itemStorage.length);
			return fixedStorage;
		}
		//Clear storage slots
		public function clearStorage():void {
			//Various Errors preventing action
			if (itemStorage == null){
				trace("Attempted to remove dfdf storage slots.");
				LOGGER.error("Cannot clear storage because it does not exist.");
			}
			else {
				LOGGER.debug("Attempted to remove {0} storage slots.", itemStorage.length);
				trace("Attempted to remove" + itemStorage.length +"storage slots.");
				itemStorage.splice(0, itemStorage.length);
			}
		}

		public function clearGearStorage():void {
			//Various Errors preventing action
			if (gearStorage == null) {
				LOGGER.error("Cannot clear gear storage because it does not exist.");
			}
			else {
				LOGGER.debug("Attempted to remove {0} gear storage slots.", gearStorage.length);
				gearStorage.splice(0, gearStorage.length);
			}
		}

		public function initializeGearStorage():void {
			//Completely empty storage array
			if (gearStorage == null) {
				//TODO refactor this to use clearGearStorage()
				LOGGER.error("Cannot clear gearStorage because storage does not exist.");
			}
			else {
				LOGGER.debug("Attempted to remove {0} gear storage slots.", gearStorage.length);
				gearStorage.splice(0, gearStorage.length);
			}
			//Rebuild a new one!
			var newSlot:ItemSlot;
			while (gearStorage.length < 45) {
				newSlot = new ItemSlot();
				gearStorage.push(newSlot);
			}
		}

		private function useItemInInventory(slotNum:int):void {
			clearOutput();
			if (player.itemSlots[slotNum].itype is Useable) {
				var item:Useable = player.itemSlots[slotNum].itype as Useable;
				if (flags[kFLAGS.DELETE_ITEMS] == 1) {
					deleteItemPrompt(item, slotNum);
					return;
				} else if (flags[kFLAGS.DELETE_ITEMS] == 2) {
					deleteItemsPrompt(item, slotNum);
					return;
				}
				if (item.canUse()) { //If an item cannot be used then canUse should provide a description of why the item cannot be used
					if (!debug) player.itemSlots[slotNum].removeOneItem();
					useItem(item, player.itemSlots[slotNum]);
					return;
				}
			}
			else {
				outputText("You cannot use " + player.itemSlots[slotNum].itype.longName + "!\n\n");
			}
			itemGoNext();
		}

		private function inventoryCombatHandler():void {
            /*if(!monster.react(monster.CON_TURNSTART)){
                combat.startMonsterTurn();
                statScreenRefresh();
                return;
            }*/
			if (player.hasPerk(PerkLib.QuickPockets) && !usedItem){
				usedItem = true;
				combat.combatMenu(false);
				return;
			}
			if (!combat.combatRoundOver()) { //Check if the battle is over.
				outputText("\n\n");
				combat.startMonsterTurn();
			}
		}

		private function deleteItems():void {
			if (flags[kFLAGS.DELETE_ITEMS] == 0) {
				flags[kFLAGS.DELETE_ITEMS]++;
			} else if (flags[kFLAGS.DELETE_ITEMS] == 1) {
				flags[kFLAGS.DELETE_ITEMS]++;
			} else if (flags[kFLAGS.DELETE_ITEMS] == 2) {
				flags[kFLAGS.DELETE_ITEMS] = 0;
			}
			inventoryMenu();
		}

		private function deleteItemPrompt(item:Useable, slotNum:int):void {
			clearOutput();
			outputText("Are you sure you want to destroy 1 " + item.shortName + "?  You won't be able to retrieve it!");
			menu();
			addButton(0, "Yes", delete1Item, item, slotNum);
			addButton(1, "No", inventoryMenu);
		}

		private function deleteItemsPrompt(item:Useable, slotNum:int):void {
			clearOutput();
			outputText("Are you sure you want to destroy " + player.itemSlots[slotNum].quantity + "x " + item.shortName + "?  You won't be able to retrieve " + (player.itemSlots[slotNum].quantity == 1 ? "it": "them") + "!");
			menu();
			addButton(0, "Yes", deleteItem, item, slotNum);
			addButton(1, "No", inventoryMenu);
		}

		public function delete1Item(item:Useable, slotNum:int):void {
			clearOutput();
			outputText("1 " + item.shortName + " has been destroyed.");
			player.destroyItems(item, 1);
			doNext(inventoryMenu);
		}

		private function deleteItem(item:Useable, slotNum:int):void {
			clearOutput();
			outputText(player.itemSlots[slotNum].quantity + "x " + item.shortName + " " + (player.itemSlots[slotNum].quantity == 1 ? "has": "have") + " been destroyed.");
			player.destroyItems(item, player.itemSlots[slotNum].quantity);
			doNext(inventoryMenu);
		}

		private function useItem(item:Useable, fromSlot:ItemSlot):void {
			item.useText();
			item.host = player;
			item.onUse();
			if (item is Armor) {
				player.armor.removeText();
				item = player.setArmor(item as Armor); //Item is now the player's old armor
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Weapon) {
				player.weapon.removeText();
				var temp:ItemSlot = new ItemSlot();
				temp.quantity = - 1;
				item = player.setWeapon(item as Weapon); //Item is now the player's old weapon
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext, null, temp);
			}
			else if (item is Jewelry) {
				player.jewelry.removeText();
				item = player.setJewelry(item as Jewelry); //Item is now the player's old jewelry
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Shield) {
				player.shield.removeText();
				item = player.setShield(item as Shield); //Item is now the player's old shield
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Undergarment) {
				if (item["type"] == 0) player.upperGarment.removeText();
				else player.lowerGarment.removeText();
				item = player.setUndergarment(item as Undergarment, item["type"]); //Item is now the player's old shield
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else {
				currentItemSlot = fromSlot;
				if (!item.useItem()) itemGoNext(); //Items should return true if they have provided some form of sub-menu.
					//This is used for Reducto and GroPlus (which always present the player with a sub-menu)
					//and for the Kitsune Gift (which may show a sub-menu if the player has a full inventory)
//				if (!item.hasSubMenu()) itemGoNext(); //Don't call itemGoNext if there's a sub menu, otherwise it would never be displayed
			}
		}

		private function takeItemFull(itype:ItemType, showUseNow:Boolean, source:ItemSlot):void {
			outputText("There is no room for " + itype.longName + " in your [inv].  You may abandon it or get rid of something else to make room.");
			menu();
			for (var x:int = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked)
					addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), replaceItem, itype, x, source).hint(generateInventoryTooltip(player.itemSlots[x]), capitalizeFirstLetter(player.itemSlots[x].itype.longName));
			}
			if (source != null && source.quantity >= 0) {
				currentItemSlot = source;
				addButton(12, "Put Back", returnItemToInventory, itype, false);
			}
			if (showUseNow && itype is Useable && !(itype as Useable).invUseOnly) addButton(13, "Use Now", useItemNow, itype as Useable, source);
			addButton(14, "Abandon", callOnAbandon); //Does not doNext - immediately executes the callOnAbandon function
		}

		private function useItemNow(item:Useable, source:ItemSlot = null):void {
			clearOutput();
			if (item.canUse()) { //If an item cannot be used then canUse should provide a description of why the item cannot be used
				useItem(item, source);
			}
			else {
				takeItemFull(item, false, source); //Give the player another chance to take this item
			}
		}

		private function replaceItem(itype:ItemType, slotNum:int, source:ItemSlot = null):void {
			clearOutput();
			if (player.itemSlots[slotNum].itype == itype) //If it is the same as what's in the slot...just throw away the new item
				outputText("You discard " + itype.longName + " from the stack to make room for the new one.");
			else { //If they are different...
				if (player.itemSlots[slotNum].quantity == 1) outputText("You throw away " + player.itemSlots[slotNum].itype.longName + " and replace it with " + itype.longName + ".");
				else outputText("You throw away " + player.itemSlots[slotNum].itype.longName + "(x" + player.itemSlots[slotNum].quantity + ") and replace it with " + itype.longName + ".");
				player.itemSlots[slotNum].setItemAndQty(itype, 1);
				if (source != null) player.itemSlots[slotNum].damage = source.damage;
			}
			itemGoNext();
		}

		public function armorRackDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 9, 18)) {
				var itemList:Array = [];
				for (var x:int = 9; x < 18; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function weaponRackDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 0, 9)) {
				var itemList:Array = [];
				for (var x:int = 0; x < 9; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function shieldRackDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 36, 45)) {
				var itemList:Array = [];
				for (var x:int = 36; x < 45; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function jewelryBoxDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 18, 27)) {
				var itemList:Array = [];
				for (var x:int = 18; x < 27; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function dresserDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 27, 36)) {
				var itemList:Array = [];
				for (var x:int = 27; x < 36; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		private function itemAnyInStorage(storage:Array, startSlot:int, endSlot:int):Boolean {
			for (var x:int = startSlot; x < endSlot; x++) {
				if (storage[x] != undefined) if (storage[x].quantity > 0) return true;
			}
			return false;
		}

		private function itemTypeInStorage(storage:Array, startSlot:int, endSlot:int, itype:ItemType):Boolean {
			for (var x:int = startSlot; x < endSlot; x++) {
				if (storage[x] != undefined) if (storage[x].quantity > 0 && storage[x].itype == itype) return true;
			}
			return false;
		}

		private function countFoodItems(storage:Array, startSlot:int, endSlot:int):Number{
			var returnVal:Number = 0;
			for (var x:int = startSlot; x < endSlot; x++) {
				if (storage[x] != undefined) if (storage[x].quantity > 0 && consumables.foodItems.indexOf(storage[x].itype) != -1) returnVal += storage[x].quantity;
			}
			return returnVal;
		}

		public function removeItemFromStorage(storage:Array, itype:ItemType):void {
			for (var x:int = 0; x < storage.length; x++) {
				if (storage[x] != undefined) {
					if (storage[x].quantity > 0 && storage[x].itype == itype) {
						storage[x].quantity--;
						return;
					}
				}
			}
		}

		public function manageEquipment():void {
			clearOutput();
			outputText("Which would you like to unequip?\n\n");
			menu();
			if (player.weapon != WeaponLib.FISTS)
				addButton(0, "Weapon", unequipWeapon).hint(player.weapon.description, capitalizeFirstLetter(player.weapon.name));
			else
				addButtonDisabled(0, "Weapon");

			if (player.shield != ShieldLib.NOTHING)
				addButton(1, "Shield", unequipShield).hint(player.shield.description, capitalizeFirstLetter(player.shield.name));
			else
				addButtonDisabled(1, "Shield");

			if (player.jewelry != JewelryLib.NOTHING)
				addButton(2, "Accessory", unequipJewel).hint(player.jewelry.description, capitalizeFirstLetter(player.jewelry.name));
			else
				addButtonDisabled(2, "Accessory");

			if (player.armor != ArmorLib.NOTHING)
				addButton(5, "Armour", unequipArmor).hint(player.armor.description, capitalizeFirstLetter(player.armor.name));
			else
				addButtonDisabled(5, "Armour");

			if (player.upperGarment != UndergarmentLib.NOTHING)
				addButton(6, "Upperwear", unequipUpperwear).hint(player.upperGarment.description, capitalizeFirstLetter(player.upperGarment.name));
			else
				addButtonDisabled(6, "Upperwear");

			if (player.lowerGarment != UndergarmentLib.NOTHING)
				addButton(7, "Lowerwear", unequipLowerwear).hint(player.lowerGarment.description, capitalizeFirstLetter(player.lowerGarment.name));
			else
				addButtonDisabled(7, "Lowerwear");

			addButton(14, "Back", inventoryMenu);
		}
		//Unequip!
		private function unequipWeapon():void {
			var temp:ItemSlot = new ItemSlot();
			temp.quantity = -1;
			takeItem(player.setWeapon(WeaponLib.FISTS), inventoryMenu, null, temp);
		}
		public function unequipArmor():void {
			if (player.armorName != "goo armor" && player.armor.id != armors.VINARMR.id) takeItem(player.setArmor(ArmorLib.NOTHING), inventoryMenu);
			else { //Valeria belongs in the camp, not in your inventory!
				player.armor.removeText();
				if (player.armor.id != armors.VINARMR.id) player.setArmor(ArmorLib.NOTHING);
				doNext(manageEquipment);
			}
		}
		public function unequipUpperwear():void {
			takeItem(player.setUndergarment(UndergarmentLib.NOTHING, UndergarmentLib.TYPE_UPPERWEAR), inventoryMenu);
		}
		public function unequipLowerwear():void {
			takeItem(player.setUndergarment(UndergarmentLib.NOTHING, UndergarmentLib.TYPE_LOWERWEAR), inventoryMenu);
		}
		public function unequipJewel():void {
			takeItem(player.setJewelry(JewelryLib.NOTHING), inventoryMenu);
		}
		public function unequipShield():void {
			takeItem(player.setShield(ShieldLib.NOTHING), inventoryMenu);
		}

		public function checkKeyItems(countOnly:Boolean = false):Boolean {
			var foundItem:Boolean = false
			var button:int = 0;
			if (!countOnly) menu();
			if (player.hasKeyItem("Tamani's Satchel")) {
				if (!countOnly) {
					addButton(button++, "Satchel", game.forest.tamaniScene.openTamanisSatchel);
				}
				foundItem = true;
			}
			if (player.hasKeyItem("Feathery hair-pin")) {
				if (!countOnly) {
					var benoitPinDesc:String;
					benoitPinDesc = "The feathery hair-pin " + game.bazaar.benoit.benoitMF("Benoit", "Benoite") + " gave to you as a present.";
					addButton(button++, "F. Hairpin", game.bazaar.benoit.equipUnequipHairPin).hint(benoitPinDesc, "Feathery Hair-pin");
				}
				foundItem = true;
			}
			if (!countOnly) addButton(14, "Back", inventoryMenu);
			return foundItem;
		}

		//Acceptable type of items
		private function allAcceptable(itype:ItemType):Boolean { return true; }

		private function armorAcceptable(itype:ItemType):Boolean { return itype is Armor; }

		private function weaponAcceptable(itype:ItemType):Boolean { return itype is Weapon; }

		private function shieldAcceptable(itype:ItemType):Boolean { return itype is Shield; }

		private function jewelryAcceptable(itype:ItemType):Boolean { return itype is Jewelry; }

		private function undergarmentAcceptable(itype:ItemType):Boolean { return itype is Undergarment; }

		//Place in storage functions
		private function pickItemToPlaceInStorage(placeInStorageFunction:Function, typeAcceptableFunction:Function, text:String, showEmptyWarning:Boolean):void {
			clearOutput(); //Selects an item to place in a gear slot. Rewritten so that it no longer needs to use numbered events
			hideUpDown();
			outputText("What item slot do you wish to empty into your " + text + "?");
			menu();
			var foundItem:Boolean = false;
			for (var x:int = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked && player.itemSlots[x].quantity > 0 && typeAcceptableFunction(player.itemSlots[x].itype)) {
					addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), placeInStorageFunction, x).hint(player.itemSlots[x].itype.description);
					foundItem = true;
				}
			}
			if (showEmptyWarning && !foundItem) outputText("\nYou have no appropriate items to put in this " + text + ".");
			addButton(14, "Back", stash);
		}

		public function generateInventoryTooltip(slot:ItemSlot):String {
			var tt:String = slot.itype.description;
			if (slot.itype.isDegradable()) {
				tt += "\nDurability: " + (slot.itype.durability - slot.damage) + "/" + slot.itype.durability;
			}
			return tt;
		}

		private var moveAll:Boolean = false;
		private function toggleMoveAll():void {
			moveAll = !moveAll;
			stash();
		}
		public function stash():void {
			callNext = stash;
			setup();
			var arr:Array = [
				[weaponRack, describe(weaponRack), player.hasKeyItem("Equipment Rack - Weapons")],
				[armourRack, describe(armourRack), player.hasKeyItem("Equipment Rack - Armor")],
				[shieldRack, describe(shieldRack), player.hasKeyItem("Equipment Rack - Shields")],
				[dresserBox, describe(dresserBox), cabin.hasDresser],
				[jewelryBox, describe(jewelryBox), player.hasKeyItem("Equipment Storage - Jewelry Box")],
			];
			showStorage(stash, itemStorage, campStorage, describe("Chest"));
			for each(var s:Array in arr){
				if(s[2]){
					showStorage(stash, gearStorage, s[0], s[1])
				}
			}
			for (var x:int = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked) {
					if (player.itemSlots[x].quantity > 0) {
						addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), curry(close,curry(stashItem,x,arr))).hint(generateInventoryTooltip(player.itemSlots[x]), capitalizeFirstLetter(player.itemSlots[x].itype.longName));
					}
					else addButtonDisabled(x, "Nothing");
				}
			}
			addButton(10, moveAll ? "Move All:ON" : "Move All:OFF", curry(close,toggleMoveAll)).hint(moveAll ? "You'll currently attempt to move the entire stack at once. Click to switch to one item at a time." : "You'll currently move one item at a time. Click to switch to moving entire stacks.");
			addButton(14, "Back", curry(close,playerMenu));
			mainView.setMainFocus(scrollPane);
			//Achievement time!
			/*
			var isAchievementEligible:Boolean = true;
			var i:int = 0;
			if (getMaxSlots() < 10) isAchievementEligible = false;
			if (getOccupiedSlots() < 10) isAchievementEligible = false;
			if (itemStorage.length < 18) isAchievementEligible = false; //Need to have all the chests!
			for (i = 0; i < itemStorage.length; i++) {
				if (itemStorage[i].quantity <= 0) isAchievementEligible = false;
			}
			for (i = 0; i < gearStorage.length; i++) {
				if (gearStorage[i].quantity <= 0) isAchievementEligible = false;
			}
			if (isAchievementEligible) awardAchievement("Item Vault", kACHIEVEMENTS.WEALTH_ITEM_VAULT, true);
			*/
		}

		private var invenPane:Block;
		private var scrollPane:CoCScrollPane;
		private function close(next:Function):void {
			mainView.resetMainFocus();
			next();
		}
		private function setupScrollPane():void {
			scrollPane = new CoCScrollPane();
			var mt:TextField = mainView.mainText;
			scrollPane.x = mt.x;
			scrollPane.y = mt.y;
			scrollPane.width = mt.width + mainView.scrollBar.width;
			scrollPane.height = mt.height;
			scrollPane.visible = true;
		}
		private function setupInvenPane():void {
			invenPane = new Block();
			invenPane.layoutConfig = {
				type: Block.LAYOUT_FLOW,
				direction: "column"
			};
			invenPane.visible = true;
		}
		private function hideMainText():void {
			hideUpDown();
			clearOutput();
			menu();
			mainView.mainText.visible = false;
			mainView.scrollBar.visible = false;
			mainView.resetTextFormat();
		}
		private function setup():void {
			hideMenus();
			clearOutput();
			spriteSelect(-1);
			menu();
			hideMainText();
			setupScrollPane();
			setupInvenPane();
			scrollPane.addChild(invenPane);
		}

		private function get campStorage():Object {
			return {start:0, end:itemStorage.length}
		}

		private function stashItem(position:int, storage:Array):void {
			var item:ItemType = player.itemSlots[position].itype;
			var available:Array = storage.filter(function(element:*, index:int, arr:Array):Boolean {
				return element[2] && (!element[0].acceptable || element[0].acceptable(item));
			});
			for each (var stor:Array in available){
				if (placeIn(gearStorage, stor[0].start, stor[0].end, position, stash, true)) {
					return;
				}
			}
			if (!placeIn(itemStorage, campStorage.start, campStorage.end, position, stash, true)) {
				close(function():void{
					outputText("You don't have any space to stash that item.");
					doNext(stash);
				});
			}
		}

		private function showStorage(back:Function, storage:Array, range:Object, text:String):void{
			var base:Block = new Block({
				layoutConfig : {
					type: Block.LAYOUT_FLOW
				},
				width: mainView.mainText.width
			});
			var tf:TextField = new TextField();
			tf.width = mainView.mainText.width * (2/5) - 5;
			tf.defaultTextFormat = mainView.mainText.defaultTextFormat;
			tf.multiline = true;
			tf.wordWrap = true;
			tf.htmlText = text;

			var block:Block = new Block({
				layoutConfig : {
					type: Block.LAYOUT_GRID,
					cols: 3,
					paddingCenter: 2
				},
				width: mainView.mainText.width * (3/5)
			});
			var btnImg:int = 0;
			for (var x:int = range.start; x < range.end; x++) {
				var button:CoCButton;
				if(storage[x].quantity == 0){
					button = new CoCButton({
						labelText: "Empty",
						bitmapClass: MainView.ButtonBackgrounds[btnImg++ % 10],
						enabled:false
					});
				} else {
					button = new CoCButton({
						labelText: storage[x].itype.shortName + " x" + storage[x].quantity,
						bitmapClass: MainView.ButtonBackgrounds[btnImg++ % 10],
						callback: curry(close, curry(pickFrom, storage, x)),
						toolTipHeader: capitalizeFirstLetter(storage[x].itype.longName),
						toolTipText: storage[x].itype.description
					});
				}
				mainView.hookButton(button);
				block.addElement(button);
			}
			block.doLayout();
			tf.height = block.height;
			tf.autoSize = TextFieldAutoSize.LEFT;
			base.addElement(tf);
			base.addElement(block);
			base.doLayout();
			invenPane.addElement(new BitmapDataSprite({
				width: mainView.mainText.width - 2,
				height:2,
				fillColor:'#000000'
			}));
			invenPane.addElement(base);
			invenPane.doLayout();
			scrollPane.update();
		}

		//Place in storage functions
		private function pickItemToPlace(back:Function,storage:Array,range:Object,text:String):void{
			var next:Function = curry(pickItemToPlace,back,storage,range,text);
			var showEmptyWarning:Boolean = false;
			var acceptable:Function = allAcceptable;
			if(range.acceptable != undefined){
				acceptable = range.acceptable;
				showEmptyWarning = true;
			}
			clearOutput(); //Selects an item to place in a gear slot. Rewritten so that it no longer needs to use numbered events
			hideUpDown();
			outputText("What item slot do you wish to empty into your " + text + "?");
			menu();
			var foundItem:Boolean = false;
			for (var x:int = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked && player.itemSlots[x].quantity > 0 && acceptable(player.itemSlots[x].itype)) {
					addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), curry(placeIn,storage,range.start,range.end,x,next)).hint(generateInventoryTooltip(player.itemSlots[x]), capitalizeFirstLetter(player.itemSlots[x].itype.longName));
					foundItem = true;
				}
			}
			if (showEmptyWarning && !foundItem) outputText("\nYou have no appropriate items to put in this " + text + ".");
			addButton(14, "Back", back);
		}

		private function placeIn(storage:Array, startSlot:int, endSlot:int, slotNum:int,next:Function, silent:Boolean = false):Boolean {
			function exit():void {
				player.itemSlots[slotNum].quantity -= (orig - qty);
				if(silent){
					next();
				} else {
					doNext(next);
				}
			}
			clearOutput();
			var x:int;
			var temp:int;
			var itype:ItemType = player.itemSlots[slotNum].itype;
			var qty:int = moveAll ? player.itemSlots[slotNum].quantity : 1;
			var orig:int = qty;
			var maxStack:int = itype.getMaxStackSize();
			for (x = startSlot; x < endSlot && qty > 0; x++) { //Find any slots which already hold the item that is being stored
				if (storage[x].itype == itype && storage[x].quantity < maxStack) {
					temp = maxStack - storage[x].quantity;
					if (qty < temp) temp = qty;
					outputText("You add " + temp + "x " + itype.shortName + " into storage slot " + num2Text(x + 1 - startSlot) + ".\n");
					storage[x].quantity += temp;
					qty -= temp;
					if (qty == 0){
						exit();
						return true;
					}
				}
			}
			for (x = startSlot; x < endSlot && qty > 0; x++) { //Find any empty slots and put the item(s) there
				if (storage[x].quantity == 0) {
					storage[x].setItemAndQty(itype, qty);
					outputText("You place " + qty + "x " + itype.shortName + " into storage slot " + num2Text(x + 1 - startSlot) + ".\n");
					qty = 0;
					exit();
					return true;
				}
			}
			exit();
			return false;
		}

		private function pickFrom(storage:Array, slotNum:int):void {
			var itype:ItemType = storage[slotNum].itype;
			if (moveAll) {
				while (storage[slotNum].quantity > 0 && (player.roomInExistingStack(itype) >= 0 || player.emptySlot() >= 0)) {
					storage[slotNum].quantity--;
					takeItem(itype, callNext, callNext, storage[slotNum], false);
				}
				stash();
			}
			else {
				var hasRoom:Boolean = player.roomInExistingStack(itype) >= 0 || player.emptySlot() >= 0;
				storage[slotNum].quantity--;
				takeItem(itype, callNext, callNext, storage[slotNum], false);
				if (hasRoom) stash();
			}
		}

		private function describe(storage:Object):String {
			var text:String = "";
			switch (storage) {
				case "Chest" :
					var chestArray:Array = [];
					if (player.hasKeyItem("Camp - Chest")) chestArray.push("a large wood and iron chest");
					if (player.hasKeyItem("Camp - Murky Chest")) chestArray.push("a medium damp chest");
					if (player.hasKeyItem("Camp - Ornate Chest")) chestArray.push("a medium gilded chest");
					if (chestArray.length == 0) text += ("Stash\nYou don't have a place to store items properly, but leaving a few things sitting at camp is probably fine.");
					else {
						text += ("Chest\nYou have " + formatStringArray(chestArray) + " to help store excess items located ");
						if (camp.homeDesc() == "cabin") text += ("inside your cabin.");
						else text += ("near the portal entrance.");
					}
					return text;
				case jewelryBox :
					text += ("Jewelry Box\nYour jewelry box is located ");
					if (flags[kFLAGS.CAMP_BUILT_CABIN] > 0 && flags[kFLAGS.CAMP_CABIN_FURNITURE_BED]) {
						if (flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER]) text += ("on your dresser inside your cabin.");
						else {
							if (flags[kFLAGS.CAMP_CABIN_FURNITURE_NIGHTSTAND]) text += ("on your nightstand inside your cabin.");
							else text += ("under your bed inside your cabin.");
						}
					}
					else text += ("next to your bedroll.");
					return text;
				case dresserBox :
					return "Dresser\nYou have a dresser inside your cabin to store nine different types of undergarments.";
				case weaponRack :
					return "Weapon Rack\nThere's a weapon rack set up here, set up to hold up to nine various weapons.";
				case armourRack :
					return "Armour Rack\nYour camp has an armor rack set up to hold your various sets of gear.  It appears to be able to hold nine different types of armor.";
				case shieldRack :
					return "Shield Rack\nThere's a shield rack set up here, set up to hold up to nine various shields.";
			}
			return text;
		}

		private const weaponRack:Object = {start: 0, end: 9, acceptable:weaponAcceptable};
		private const armourRack:Object = {start: 9, end: 18, acceptable:armorAcceptable};
		private const jewelryBox:Object = {start: 18, end: 27, acceptable:jewelryAcceptable};
		private const dresserBox:Object = {start: 27, end: 36, acceptable:undergarmentAcceptable};
		private const shieldRack:Object = {start: 36, end: 45, acceptable:shieldAcceptable};
	}
}