code:
package classes.Scenes.Places.TelAdre {
import classes.GlobalFlags.kFLAGS;
import classes.ItemType;
import classes.display.SpriteDb;

public class WeaponShop extends Shop {
	public function WeaponShop() {
		super();
		sprite = SpriteDb.s_weaponsmith;
	}

	override protected function inside():void {
		clearOutput();
		outputText("The high pitched ring of a steel hammer slamming into hot metal assaults your ears as you walk up to the stand.  Sparks are flying with every blow the stand's owner strikes on his current work.  The metal is glowing red hot, and the hammer falls with the relentless, practiced precision of an experienced blacksmith's guiding hand.  " + (noFur() ? "A short gray and white tail" : "Thick gray and white fur") + " ruffles as the blacksmith stands up, revealing the details of his form to you.  He's one of the dog-people that inhabits this city, though his " + (noFur() ? "tail" : "fur") + " and ears remind you of a dog one of your friends had growing up called a husky.  The blacksmith is anything but husky.  He's fairly short, but lean and whip-cord tough.  His right arm is far more thickly muscled than his left thanks to his trade, and he walks with a self-assured gait that can only come with age and experience.\n\n");
		outputText("His piercing blue eyes meet yours as he notices you, and he barks, \"Buy something or fuck off.\"\n\nWhat do you buy?");
		menu();
		addItemBuyButton(consumables.W_STICK);
		addItemBuyButton(weapons.CLAYMOR);
		addItemBuyButton(weapons.WARHAMR);
		addItemBuyButton(weapons.KATANA);
		addItemBuyButton(weapons.SPEAR);
		addItemBuyButton(weapons.WHIP);
		addItemBuyButton(weapons.W_STAFF);
		addItemBuyButton(weapons.S_GAUNT);
		addItemBuyButton(weapons.DAGGER);
		addItemBuyButton(weapons.SCIMITR);
		addItemBuyButton(weapons.MACE);
		addItemBuyButton(weapons.FLAIL);
		if (player.hasKeyItem("Sheila's Lethicite") || flags[kFLAGS.SHEILA_LETHICITE_FORGE_DAY] > 0) {
			addButton(13, "ScarBlade", forgeScarredBlade);
		}
		addButton(14, "Leave", telAdre.telAdreMenu);
	}

	protected override function confirmBuy(itype:ItemType = null, priceOverride:int = -1, keyItem:String = ""):void {
		clearOutput();
		outputText("The gruff metal-working husky gives you a slight nod and slams the weapon down on the edge of his stand.  He grunts, \"That'll be " + itype.value + " gems.\"");
		super.confirmBuy(itype);
	}

	private function forgeScarredBlade():void {
		if (player.hasKeyItem("Sheila's Lethicite")) {
			forgeScarredBladeStart();
		}
		//remove Sheila's Lethicite key item, set sheilacite = 3, start sheilaforge timer, increment once per day at 0:00
		if (game.time.days - flags[kFLAGS.SHEILA_LETHICITE_FORGE_DAY] < 14) {
			forgeScarredBladeMiddle();
		}
		if (game.time.days - flags[kFLAGS.SHEILA_LETHICITE_FORGE_DAY] >= 14) {
			forgeScarredBladeEnd();
		}
	}

	private function forgeScarredBladeStart():void {
		clearOutput();
		outputText("The blacksmith turns an appraising eye on you as you approach him without looking at any of the weapons on display.\n\n");
		outputText("\"What do you want?\" he says, with characteristic gruffness.\n\n");
		outputText("You pull out the dark purple crystal you received from Sheila and ask if it would be possible to alloy a blade from it.  He doesn't move to take it from your outstretched hand just yet, but you can see a hint of interest in the softening of his features.	\"That's a lethicite.  Where'd you get it?\" asks the smith.\n\n");
		outputText("\"Stole it from a demon,\" you lie.\n\n");
		outputText("He considers for a moment more before responding.  \"Well done, then.\"	At that, he takes the crystal gingerly from your hand.	\"Never worked with this before.  I promise nothing, but come back in two weeks.  I should have an update for you.\"\n\n");
		flags[kFLAGS.SHEILA_LETHICITE_FORGE_DAY] = game.time.days;
		player.removeKeyItem("Sheila's Lethicite");
		doNext(inside);
	}

	private function forgeScarredBladeMiddle():void {
		clearOutput();
		outputText("The weaponsmith looks up from the forge as you enter.  \"Oh, it's you.  I'm not done yet.\"	With a gesture, he dismisses you.  You can only content yourself with looking at the finished products.\n\n");
		doNext(inside);
	}

	private function forgeScarredBladeEnd():void {
		clearOutput();
		outputText("The smith looks up as you enter, and you could swear the already-thin, no-nonsense line of his mouth becomes even tighter.	\"It's you.	Come here.\"\n\n");
		outputText("Obligingly, you approach him, though the forge's heat is stifling.	\"I finished.  The crystal impregnated the metal easily, but the blade itself... just have a look.\"  He picks up a tatty scabbard from a pile of half-finished weapons and holds it to you - as he does, you notice for the first time the numerous bandages on his hands.	A bit wary, you unsheathe the blade halfway; it hisses against the oiled leather as you draw it.  The revealed form of the weapon is slim, curved rakishly, and glows with an umbral light against the backdrop of the lit forge, but its broad side is covered in deep lines.\n\n");
		outputText("\"Damnedest thing.  I couldn't straighten the blade for the life of me - with every hammer blow it would leap, vibrating, from the anvil, and warp somewhere else, adding a new twist for each one I took out.  After a few failures, I settled for a backsword design and channeled the bending toward the flat edge.  That's not the uncanny bit though.  You can see how sharp it is; the edge fairly shaped itself with just a touch of the grinder.  I haven't honed it - didn't need to.  But when I tried to etch a design just above the hilt, it would slide under the stencil, leaving a gouge on the blade.\"\n\n");
		outputText("Closer examination reveals the veracity of his claim: all the numerous scratches and flaws on the blade have their origins right above the tang, from the smith's abortive attempts at decoration.	Yet though several ugly gashes stop just short of the edge, none of them actually break the perfect arc, as if cutting were all the blade cared about.\n\n");
		outputText("\"Damnedest thing,\" he repeats, breaking your train of thought.  \"Every time the blade slipped, it would twist toward my hands.  It's as if it's alive and eager to find flesh.  Truth be told... I was debating whether to turn it over to the Covenant and tell you the crystal couldn't be used.  But you're here, so take it and go.\"	Giving you barely enough time to sheathe the blade again, he places a strong hand against your back and all-but-pushes you out to the street.\n\n");
		inventory.takeItem(weapons.SCARBLD, finishTakingScarredBlade, inside);
	}

	private function finishTakingScarredBlade():void {
		flags[kFLAGS.SHEILA_LETHICITE_FORGE_DAY] = -1;
		inside();
	}

}
}

license: unknown


code:
package classes.Scenes.Places.TelAdre {
import classes.GlobalFlags.kFLAGS;
import classes.GlobalFlags.kGAMECLASS;
import classes.ItemType;
import classes.Items.Armor;
import classes.display.SpriteDb;

public class YvonneArmorShop extends Shop {
	public function YvonneArmorShop() {
		super();
		sprite = SpriteDb.s_yvonne;
	}

	protected override function inside():void {
		clearOutput();
		outputText("The interior of the armory is blisteringly hot, filled with intense heat from the massive forge dominating the far side of the shop.  The bellows are blowing hard as a tall " + (noFur() ? "dog-eared" : "german-shepherd") + " woman works the forge.  Incredibly, she's wearing nothing aside from a ragged leather apron.  It bulges from the front, barely containing her obscene proportions as it protects them from the heat of her forge.  She pulls a piece of metal from the forge and strikes it a few times with a hammer bigger than your head, then tosses it in a bucket filled with water, steam boiling out of it from the hot metal.  At last, the sweating forgemistress notices you and turns around, her breasts jiggling wildly.\n\n");
		outputText("\"What can I make for you?  Platemail?  Or something that breathes a little easier?\" Yvonne asks, fanning herself.");

		menu();
		addItemBuyButton(armors.CHBIKNI);
		addItemBuyButton(armors.FULLCHN);
		addItemBuyButton(armors.FULLPLT);
		addItemBuyButton(armors.INDECST);
		addItemBuyButton(armors.LTHRROB);
		addItemBuyButton(armors.SCALEML);
		addItemBuyButton(armors.SAMUARM);
		addItemBuyButton(shields.BUCKLER);
		addItemBuyButton(shields.KITE_SH);
		addItemBuyButton(shields.GREATSH);
		addItemBuyButton(shields.TOWERSH);

		if (player.hasKeyItem("Dragon Eggshell")) {
			outputText("\n\nThough the pieces on display have their arguable attractions, none of them really interest you.  Yvonne taps her foot impatiently.  \"Well, I could make you something to order... if you have any decent materials, cutie.  200 gems.\"");
			if (player.gems < 200) {
				outputText("\n\nYou can't afford that!");
			}
			else {
				addButton(12, "Eggshell", game.emberScene.getSomeStuff);
			}
		}
		addButton(13, "Flirt", yvonneFlirt);
		addButton(14, "Leave", telAdre.telAdreMenu);
	}

	protected override function confirmBuy(itype:ItemType = null, priceOverride:int = -1, keyItem:String = ""):void {
		spriteSelect(64);
		clearOutput();
		if (itype is Armor) {
			outputText("Yvonne gives you a serious look, then nods.  She pulls the armor off a rack and makes a few adjustments, banging away with her massive hammer to ensure a perfect fit.  The entire time, she's oblivious to the movements of her massive breasts, accidentally exposing her impressive nipples multiple times.\n\n");
			outputText("She finishes and turns to you, smiling broadly, \"Now, that will be " + itype.value + " gems, unless you want to change your mind?\"");
		}
		else {
			outputText("Yvonne gives you a serious look, then nods.  She pulls the shield off a rack and shows it to you.\n\n");
			outputText("She smiles broadly, \"Now, that will be " + itype.value + " gems, unless you want to change your mind?\"");
		}
		super.confirmBuy(itype);
	}

	//[Flirt]
	private function yvonneFlirt():void {
		spriteSelect(64);
		clearOutput();
		outputText("You step closer, glancing from her bulging, barely contained tits to her pouting lips and expressive, violet eyes.  A shock of sweat-matted auburn hair obscures part of her face, but the tall, buxom blacksmith nervously brushes it aside as she watches.  Once you're close enough to touch, you quietly and sincerely proclaim, \"You're the most beautiful piece of craftsmanship in this entire store.\"");
		outputText("\n\nYvonne steps back, and you swear you can see a blush blooming " + (noFur() ? "on her cheeks" : "through her fur") + ", a fiery glow of embarrassment that spreads to the upper curve of her immense mammaries.  She folds her arms over her apron, unintentionally smushing those gigantic tits closer together and deepening her cleavage into a canyon. An immense sigh causes the plush plateau to sway pendulously as Yvonne answers, \"");
		dynStats("lus", (10 + player.lib / 10));

		// Brain no want to work out the boolean logic shit here, broken out to ensure it will work as intended.
		if (player.cockTotal() === 0) {
			outputText("Sorry, but you don't look like you'd be much fun.");
			outputText("\"");
			doNext(inside);
			return;
		}
		else if (player.tallness > 65 && !flags[kFLAGS.LOW_STANDARDS_FOR_ALL]) {
			outputText("Sorry, but you don't look like you'd be much fun.");
			outputText("\"");
			doNext(inside);
			return;
		}
		else if (player.cockThatFits(75) === -1 && !flags[kFLAGS.LOW_STANDARDS_FOR_ALL]) {
			outputText("Sorry, but you don't look like you'd be much fun.");
			outputText("\"");
			doNext(inside);
			return;
		}

		if (flags[kFLAGS.YVONNE_FUCK_COUNTER] === 0) {
			outputText("Well, I could use a quick fuck.  If you meant what you said, go change the sign to say 'out' please.");
		} else {
			outputText("You want to go again, huh?  I do love working up a sweat...");
		}
		outputText("\"");
		//[Fuck] [Nevermind]
		menu();
		addButton(0,"Fuck Her", fuckYvonneInZeBlacksmith);
		addButton(1,"Nevermind", backOutOfYvonneFuck);
	}

	//[Nevermind]
	private function backOutOfYvonneFuck():void {
		spriteSelect(64);
		clearOutput();
		outputText("You politely decline, not wanting to interrupt her work.  Yvonne sighs and begins to pump the bellows, muttering, \"Then you'd better be buying something!\"");
		doNext(inside);
	}

	//[Fuck]
	private function fuckYvonneInZeBlacksmith():void {
		spriteSelect(64);
		clearOutput();
		//X = cock that fits!
		var x:Number = player.cockThatFits(75);
		if (x < 0) {
			x = 0;
		}
		//Used for the new cock stuff
		var y:Number = x + 1;
		outputText("You walk over to the door and find a sign hanging in front of the window.  The side facing indoors has 'out' on it.  There's also a 'closed' sign hanging to the side of the doorframe.  You take the simple wood plaque in hand and flip it over - can't have anybody walking in on your sexual hijinks, can you?");
		outputText("\n\nA" + (noFur() ? "" : " fuzzy,") + " calloused hand grabs you by the scuff of the neck, lifts you off the ground and pushes you against the wall, slamming you into it forcefully enough that some weapons hanging nearby rattle dangerously.  A hot puff of breath hits your cheek" + (noFur() ? "" : ", Yvonne's wet, canine nose bumping against your ear") + " as she pants in your face.  She closes, and you feel her bare, sweat-soaked breasts sliding up and down your back, holding you up as firmly as her iron grip.  Yvonne's long, smooth tongue licks you from collarbone to chin, lapping up the sweat that's already starting to bead, the heat of the simmering forge-fires and your companion's well-warmed, powerful frame long since getting to you.");
		outputText("\n\nA distinctly feminine scent wafts up to your nostrils, intermingled with the blacksmith's own pungent body-odor, strong enough to make your head swim.  Yvonne's free hand begins removing your [armor], the blacksmith's confident motions suggesting she's had plenty of experience at this.  The aroma of the super-stacked bitch's estrus increases to the point where it nearly overpowers her salty sweat-smell, her nipples pressing hard into your back.  [EachCock] grows hard from the forceful attention, pinned between the wall and your belly.  Finished with your gear, Yvonne nips your neck and says, \"Nice package, ");
		if (player.cockArea(x) < 20) {
			outputText("runt");
		} else if (player.cockArea(x) < 40) {
			outputText(player.mf("boy", "girl"));
		} else if (player.cockArea(x) < 60) {
			outputText("big " + player.mf("boy", "girl"));
		} else {
			outputText(player.mf("stud", "breeder"));
		}
		outputText(".\"");
		outputText("\n\nThe forge-mistress abruptly releases you and steps away, the supporting cushion of her breasts no longer there to help balance you.  After a moment of confused stumbling, you catch yourself and turn around, curious as to just what the buxom bitch is doing.");
		outputText("\n\nYvonne is on the ground on all fours.  Her tail is sticking nearly straight up, waving back and forth excitedly as she presents her curvy rump to you.  Surprisingly, her ass is much less muscular than her upper body, with a pair of pillowy buttcheeks that nearly conceal her soaked cunny from view.  You aren't sure if it's lubricant from her arousal, or sweat from working the forge all day, but Yvonne's thighs are absolutely drenched with moisture; a veritable slip n' slide of wetness that beckons you to bury your bone in the canine's feminine entrance.  She glances back over her shoulder, a submissive glint in her eyes as she begs, \"Come on, be my alpha.  This bitch needs a hot, wet fuck.  Do it!\"  What an odd dichotomy - one moment she's throwing you around, the next, begging to be mounted.  For all her power, it seems Yvonne still wants to be taken as a meek bitch.");
		outputText("\n\nYou sidle up to the larger woman and begin aligning [oneCock] with her mammoth buns, the sweltering, pheromone-laced stink pouring from her body making it difficult not to fall on top of her and rut.  Her huge tits are squished against the floor, squeezing out obscenely to either side of the blacksmith's lithe, muscular torso.  When you push inside, her slick wet cunt squeezes your [cock " + y + "] powerfully but affectionately.  Her potent vaginal muscles work your [cock " + y + "] over, tightly embracing your turgid dickflesh as you begin to fuck her properly, plowing her sweat and love-juice soaked folds even while you struggle to reach up for her incredible breasts.");
		outputText("\n\nYou get a handhold on the soft chest-flesh and begin to massage at what you can find, releasing appreciative moans from your partner.  Unfortunately, her furiously-wagging tail bludgeons you across the nose over and over, and you're forced to block it with one arm so that you can ream her snatch unimpeded by the woman's canine instincts.  She growls, but doesn't stop you.  You can see the muscles in her arms quivering, shaking, struggling to maintain her posture in spite of the overwhelming pleasure your [cock " + y + "] is inflicting upon her poor womanhood.");
		outputText("\n\nA shiver runs through the dog-" + (noFur() ? "girl" : "morph") + "'s entire body, culminating in a cock-wringing contraction that ripples through her cunt, milking you with her slippery twat.  It works, and you lean over her prostrate form as you bottom out inside her, her sweat-matted " + (noFur() ? "hair" : "fur") + " smearing your face with her scent as you cum.  ");
		if (player.hasKnot(x)) {
			outputText("Your knot fills, locking you inside her, securely blocking any escape for the jizz you're now filling her depths with.  Yvonne sighs dreamily, \"Just right...\" while spunk slides into her birth canal to infiltrate her womb.[if (cumQuantity > 500) \"  The pearly goop spatters into her womb with egg-inseminating force, filling her beyond her wildest expectations.\"][if (cumQuantity > 1000) \"  The blacksmith cries out in pain and pleasure, her belly rounding with your liquid, taking on a more pregnant, stuffed-silly look.\"][if (cumQuantity > 2000) \"  Thanks to your knot, not a single drop escapes, and soon Yvonne's belly is as fat as her tits, cum-bloated in the extreme, a sloshing auburn tub packed with ivory sperm.\"]");
		} else {
			outputText("Your jizz bubbles out to fill her depths, the spunk surging through her as it moves towards her womb.  Yvone sighs dreamily, \"Ahhhh...\" while you empty your [balls] inside her unprotected womanhood.[if (cumQuantity > 500) \"  The pearly goop spatters into her uterus with egg-inseminating force, filling the bitch beyond her wildest expectations.\"][if (cumQuantity > 1000)  The blacksmith cries out in pain and pleasure, her belly rounding with your liquid, looking positively pregnant.  Her twat begins to dribble sperm, creampied beyond belief.][if (cumQuantity > 2000) \"  Unfortunately, as your virility makes itself known, Yvonne's body hits its limit, and jets of ivory spooge squirt from all sides of her cunny, dribbling into a pearly puddle on the floor.\"]");
		}
		//still no new pg
		outputText("  With a thoroughly cream-stuffed twat beneath you, you ");
		if (player.hasKnot(x)) {
			outputText("pop");
		} else {
			outputText("pull");
		}
		outputText(" out, accompanied by a exhalation of female pleasure.");
		outputText("\n\nYvonne staggers up on her " + (noFur() ? "feet" : "footpaws") + ", groaning the whole time, a trail of white dribbling on the floor behind her.  Her tail wags happily, and she grabs you, pulling you into her sweaty bosom as she affectionately squeezes your [butt].  You aren't released until you feel dizzy, half-suffocated by her preponderance of breast-tissues and potent pheromones.");
		outputText("\n\nYvonne tosses you your gear, and you dress in a daze.  Before you've completely finished, she's pushing you out into the street, covered in sex-stink and stumbling over your own [feet].  She calls out after you, \"Thanks babe, I gotta mop this mess up!\"");
		player.orgasm('Dick');
		dynStats("sen", -1);
		flags[kFLAGS.YVONNE_FUCK_COUNTER]++;
		doNext(camp.returnToCampUseOneHour);
	}
}
}


code:
package classes.Scenes.Places  {
	import classes.BaseContent;
import classes.CoC;
import classes.GlobalFlags.*;
import classes.Scenes.API.Encounter;
import classes.Scenes.API.Encounters;
import classes.Scenes.API.FnHelpers;

/**
	 * ...
	 * @author ...
	 */
	public class TownRuins extends BaseContent {
		public function TownRuins() {}

		public function rackCount():int {
			var temp:int = 0;
			if (player.hasKeyItem("Equipment Rack - Armor")) temp++;
			if (player.hasKeyItem("Equipment Rack - Weapons")) temp++;
			if (player.hasKeyItem("Equipment Rack - Shields")) temp++;
			return temp;
		}

		public function totalDismantled():int {
			var temp:int = 0;
			temp += flags[kFLAGS.TOWN_RUINS_HOUSES_DISMANTLED];
			if (flags[kFLAGS.TOWN_RUINS_TOWNHALL_SCAVENGE_PROGRESS] >= 4) temp++;
			if (flags[kFLAGS.TOWN_RUINS_SHOP_SCAVENGE_PROGRESS] >= 4) temp++;
			return temp;
		}

		private var furnitureFoundToday:String = "";

		public function isDiscovered():Boolean {
			return flags[kFLAGS.AMILY_VILLAGE_ACCESSIBLE] > 0;
		}

		//Encounters
		//[Ruined Village]
		//[Exploring the Lake]
		public function discoverAmilyVillage():void {
			clearOutput();
			outputText(images.showImage("location-townruins-path"));
			outputText("As you roam the shores of the lake, you find your footsteps echoing as though you were stepping on wood rather than squishing in the sandy mud of the shore. Curious, you squat down and brush the soil away, revealing the rotting form of a wooden plank. Looking carefully at the ground underfoot, you realize that it is part of a pathway - the kind that villages make to provide easier access to and from muddy rivers, lakes and beaches. You believe you can make out the rest of the path clearly enough to follow it to its end.\n\n");
			outputText("Do you follow the pathway?");
			doYesNo(exploreAmilyVillage,dontExploreAmilyVillage);
		}

		private function dontExploreAmilyVillage():void { //[No]
			clearOutput();
			outputText(images.showImage("location-townruins-path"));
			outputText("Standing up, you turn and walk away. You presume from the state of the pathway that the village at the other end must either be in dire straits, abandoned, or overwhelmed by demons. In other words, it's no safe place for a traveler like you.\n\n");
			doNext(camp.returnToCampUseOneHour);
		}

		private function exploreAmilyVillage():void { //[Yes]
			clearOutput();
			outputText(images.showImage("location-townruins"));
			outputText("You follow the overgrown path inland, away from the shore of the lake. You pass through thick trees, struggling not to lose the path, before finally reaching what is clearly the end.  In front of you lie crumbling walls, broken and scattered by the wind and rain... and by other forces entirely. Beyond them are houses that have been torn apart, burned or collapsed. This was clearly once a village, but it was devastated at some point in the past. Demon attack is the first possibility that leaps into your mind. You examine the ruins for a time, and then decide to head back to camp. You don't think it would be wise to investigate here without preparing first.\n\n");
			outputText("(\"Town Ruins\" added to Places menu.)");
			flags[kFLAGS.AMILY_VILLAGE_ACCESSIBLE] = 1; //set village unlock flag
			doNext(camp.returnToCampUseOneHour);
		}
		private var _explorationEncounter:Encounter = null;
		public function get explorationEncounter():Encounter {
			const fn:FnHelpers = Encounters.fn;
			return _explorationEncounter ||= Encounters.group({
				name:"shouldra",
				chance:0.5,
				when: function():Boolean {
					return flags[kFLAGS.SHOULDRA_PALADIN_MAIDEN_COUNTDOWN] == 0
						   && rackCount() >= 2
						   && !game.shouldraFollower.followerShouldra()
						   && flags[kFLAGS.SHOULDRA_FOLLOWER_STATE] != .5;
				},
				call: game.shouldraScene.shouldraGreeting
			},{
				name:"rack",
				chance:0.2,
				when:function():Boolean {
					return rackCount()<3;
				},
				call: findRack
			},{
				name: "amily",
				when: function():Boolean {
					return flags[kFLAGS.AMILY_VILLAGE_ENCOUNTERS_DISABLED] != 1;
				},
				call: game.amilyScene.encounterAmily
			},{
				name:"scavenge",
				when: function():Boolean {
					return flags[kFLAGS.AMILY_VILLAGE_ENCOUNTERS_DISABLED] == 1;
				},
				call: scavengeTownRuinsOption
			});
		}
		public function exploreVillageRuin():void {
			flags[kFLAGS.AMILY_VILLAGE_EXPLORED]++;
			clearOutput();
			explorationEncounter.execEncounter();
		}

	private function findRack():void {
		var rack:Number;
		var rackArray:Array = [];
		if (!player.hasKeyItem("Equipment Rack - Armor")) rackArray[rackArray.length] = 0;
		if (!player.hasKeyItem("Equipment Rack - Weapons")) rackArray[rackArray.length] = 1;
		if (!player.hasKeyItem("Equipment Rack - Shields")) rackArray[rackArray.length] = 2;
		rack = rackArray[rand(rackArray.length)];
			outputText(images.showImage("item-rack"));
		outputText("While picking through the ruined houses and abandoned structures of this dilapidated village, you manage to find something useful!  There's an intact but empty ");
		switch (rack) {
				case 0: outputText("armor"); break;
				case 1: outputText("weapon"); break;
				case 2: outputText("shield"); break;
				default:outputText("undefined");
		}
		outputText(" rack here.  It looks like it could hold nine different ");
		switch (rack) {
				case 0: outputText("armors"); break;
				case 1: outputText("weapons"); break;
				case 2: outputText("shields"); break;
				default:outputText("undefined");
		}
		outputText(".  You check it over and spot an easy way to fold it up for transport.  This would be a fine addition to your camp, so you pack it up and haul it back.");
		switch (rack) {
				case 0: player.createKeyItem("Equipment Rack - Armor",0,0,0,0); break;
				case 1: player.createKeyItem("Equipment Rack - Weapons",0,0,0,0); break;
				case 2: player.createKeyItem("Equipment Rack - Shields",0,0,0,0); break;
				default:outputText("  Please let Kitteh6660 know about this bug.");
		}
		doNext(camp.returnToCampUseOneHour);
	}

		private function scavengeTownRuinsOption():void { // SCAVENGING
			outputText(images.showImage("location-townruins"));
			if (flags[kFLAGS.TOWN_RUINS_SCAVENGE_CONSIDERED] == 0) {
				outputText("Even though the village is in ruins, there are plenty of resources to salvage; wood, stones, and nails are all there for you to haul. You contemplate which structure you should focus on salvaging for resources to bring to your camp.");
				flags[kFLAGS.TOWN_RUINS_SCAVENGE_CONSIDERED] = 1;
			}
			else outputText("Once again, you return to the ruined village, pondering which structure to salvage.");
			if (totalDismantled() < 12) {
				outputText("\n\n");
				if (totalDismantled() < 8) {
					outputText("There are burnt-down houses, smashed-in doorways, ripped-off roofs... everything is covered with dust and grime. ");
					if (totalDismantled() >= 1) outputText(Num2Text(totalDismantled()) + " of the structures " + (totalDismantled() == 1 ? "is" : "are") + " completely stripped, leaving only " + (totalDismantled() == 1 ? "its foundation" : "their foundations") + ".");
				}
				else {
					outputText("Most of the ruined houses are gone, leaving only foundations in their wake. ");
					if (totalDismantled() >= 10) outputText("It won’t be long until the ruined village is completely devoid of structures.");
				}
				menu();
				if (flags[kFLAGS.TOWN_RUINS_HOUSES_DISMANTLED] < 10) addButton(0, "House #" + flags[kFLAGS.TOWN_RUINS_HOUSES_DISMANTLED], dismantleHouse);
				else addButtonDisabled(0, "House", "You have already dismantled all the houses.");
				if (flags[kFLAGS.TOWN_RUINS_TOWNHALL_SCAVENGE_PROGRESS] < 4) addButton(1, "Town Hall", dismantleTownHall);
				else addButtonDisabled(1, "Town Hall", "That building is no more. It's stripped down to its foundations.");
				if (flags[kFLAGS.TOWN_RUINS_SHOP_SCAVENGE_PROGRESS] < 4) addButton(2, "Shop", dismantleShop);
				else addButtonDisabled(2, "Shop", "That building is no more. It's stripped down to its foundations.");
				addButton(4, "Leave", camp.returnToCampUseOneHour);
			}
			else doNext(camp.returnToCampUseOneHour);
		}

		private function dismantleHouse():void {
			clearOutput();
			outputText(images.showImage("location-townruins-house"));
			outputText("A house seems like a good start. You walk over to one of the ruined houses and enter to check for any useable furniture you could take.");
			if (flags[kFLAGS.TOWN_RUINS_HOUSE_FURNITURE_FOUND] == 0 && flags[kFLAGS.TOWN_RUINS_HOUSE_SCAVENGE_PROGRESS] == 0 && rand(100) < 80) findFurniture("house");
			dismantleMainText(kFLAGS.TOWN_RUINS_HOUSE_SCAVENGE_PROGRESS, "house");
		}

		private function dismantleTownHall():void {
			clearOutput();
			outputText(images.showImage("location-townruins-townhall"));
			outputText("The remains of what must have once been the town hall catch your eye.  Of all the ravaged structures, this is the largest and most likely to yield something of use. You enter the town hall and check for any useable furniture you could take.");
			if (flags[kFLAGS.TOWN_RUINS_TOWNHALL_FURNITURE_FOUND] == 0 && flags[kFLAGS.TOWN_RUINS_TOWNHALL_SCAVENGE_PROGRESS] == 0) findFurniture("town hall");
			dismantleMainText(kFLAGS.TOWN_RUINS_TOWNHALL_SCAVENGE_PROGRESS, "town hall");
		}

		private function dismantleShop():void {
			clearOutput();
			outputText(images.showImage("location-townruins-shop"));
			outputText("Your eyes are drawn to what was once a shop, judging by its vandalized sign. Who knows what might be inside? You enter and check for anything useful to take.");
			if (flags[kFLAGS.TOWN_RUINS_TOWNHALL_FURNITURE_FOUND] == 0 && flags[kFLAGS.TOWN_RUINS_TOWNHALL_SCAVENGE_PROGRESS] == 0) findFurniture("shop");
			dismantleMainText(kFLAGS.TOWN_RUINS_SHOP_SCAVENGE_PROGRESS, "shop");
		}

		private function dismantleMainText(progress:int = 0, buildingDesc:String = ""):void { //Main text goes here
			var nails:int = 0;
			var wood:int = 0;
			var stones:int = 0;
			var resourceGainText:Array = [];
			outputText("\n\n");
			if (!player.hasKeyItem("Carpenter's Toolbox")) { //No toolbox? Cancel!
				outputText("You look around, inspecting the empty house. You could probably get some ressources from breaking down the roof and walls, but how are you going to demolish them? With your fists? A toolbox would definitely help...");
				doNext(camp.returnToCampUseOneHour);
				return;
			}
			if (flags[progress] == 0) { //Have toolbox?
				outputText("After checking for furniture, you set down your toolbox, open it and take out a tool belt you put around your waist. Then you load it with the necessary tools. Safety first, of course! You put on your safety goggles and hard hat. Time to get started with looting some useful resources.");
				outputText("\n\nYou should probably start with the roof and work down from there. From the looks of it, it’s made up from wooden frames that have been nailed together. It’s possible that the roof once had some kind of thatch to keep the rain out. Whatever it was must have burned away however, leaving behind the bare wooden frame. You’ll have to reach to reach up there to begin your work.");
				if (!(player.isTaur() || player.canFly())) {

					if (player.hasKeyItem("Ladder")){
						outputText("\n\nYou haul over the ladder you previously constructed, lean it against a wall, giving it an experimental shake to confirm the ladder is safe to climb on. ");
					}
					else {
						outputText("\n\nYou gather some loose pieces of wood that look long and thick enough to be of use and cut up one of the long pieces into equal parts to be used as rungs. Next, you assemble two long pieces of wood and arrange the smaller pieces, using a measuring tape to ensure that the rungs are spaced apart evenly. ");
						if (player.keyItemv1("Carpenter's Toolbox") >= 24) {
							outputText("You take some nails out of your tool belt and drive them into place.");
							player.addKeyValue("Carpenter's Toolbox", 1, -24);
						}
						else outputText("You realize you are short on nails but you make do by picking up some loose nails that must have come off one of the destroyed sections. Once you have found a sufficient amount of nails in usable condition, you hammer them into place.");
						outputText("\n\nTo ensure the ladder is going to be stable, you saw off the broken ends of the long wooden pieces so they are flat and place a flat piece of wood against the ends of two long pieces. You then take out a metal L-square ruler to check if it’s perfectly equal and make some adjustments as necessary. With the ladder now assembled, you prop it up against a wall and test the stability by giving it an experimental shake and adjust the angle. Yes, the ladder looks safe to climb on. ");
						outputText("Gained Key Item: Ladder! ");
						player.changeFatigue(50);
						player.createKeyItem("Ladder", 0, 0, 0, 0);
					}
					outputText("You climb up the ladder and grab onto the roof.");
				}
				else if (player.canFly()) outputText("\n\nNothing is out of reach when you have wings that allow you to fly! You flap your wings to fly off the ground and land on the roof.");
				else if (player.isTaur() || player.isDrider()) outputText("\n\nHaving the lower body of an animal is giving you an advantage here. You rear up to get a boost to your reach, and plant your front [feet] flat against the wall for stability.");
				//Merge checks here!
				outputText("With the roof now in your reach, you decide to start by sawing the wood apart. You pull out a saw from your tool belt and work on sawing away the wooden roof frames, sorting the broken and workable pieces of wood in separate piles. With the roof successfully removed and dismantled, you separate any pieces of wood still nailed-together, carefully removing the nails. A good amount of them are in a good enough condition to be reused in your future construction projects, so you put them in the nail compartment of your toolbox. You bind up the usable wood into a pile and finally haul it");
				if (furnitureFoundToday) outputText(", along with the newly-found " + furnitureFoundToday + " ");
				outputText(" to your camp.");
				nails = 10 + rand(20) + Math.floor(rand((player.str + player.inte) / 4));
				wood = 10 + rand(10) + Math.floor(rand((player.str + player.inte) / 8));
			}
			else if (flags[progress] == 1) {
				outputText("Now that the roof has been removed, you can safely dismantle the interior walls. You pull out a hammer and chisel from your tool belt, angle the chisel against one of the walls and strike the handle, causing the plaster to break away. With the plaster broken off, you strike the exposed section and it collapses, sending out a cloud of chipped plaster and dust. Once the cloud has cleared, you chisel away the remaining section of the wall and knock it down. Next, you pull up the wooden studs from the floor and lay them neatly on the ground. You repeat the process for the rest of the interior walls. With the interior walls now removed, you comb through the heaps of debris for intact stone bricks. The process takes you an entire hour.\n\n");
				outputText("You pick up the stone bricks, place them in a neat pile on a pallet and tie them together along with the wooden pieces before finally hauling the newly-scavenged resources home.");
				wood = 10 + rand(10) + Math.floor(rand((player.str + player.inte) / 8));
				stones = 5 + rand(5) + Math.floor(rand((player.str + player.inte) / 20));
			}
			else if (flags[progress] == 2) {
				outputText("With the interior of the building hollow and the roof removed you can begin dismantling the frame. Taking out your hammer and chisel you begin to chip away at the mortar keeping the stone wall together, slowly weakening the structure with each strike. Once you reach the end you look back at your progress, piles of chipped mortar line the floor next to the wall. Taking one last look at it, you take a place inside the hollow structure and push the wall outwards, sending it crashing down, upon impact with the ground it breaks into debris that consists of stone and left-over mortar. Repeating this process for the other sides you get a good look at the wooden studs that have been freed from the surrounding stone; it takes " + (player.str < 80 ? "great" : "a bit of") + " effort, but you manage to pluck them from the ground and arrange them in a neat pile to be hauled off back to camp.");
				player.changeFatigue(Math.max(10, 40 - Math.floor(player.str / 5)));
				wood = 10 + rand(10) + Math.floor(rand((player.str + player.inte) / 8));
				stones = 5 + rand(5) + Math.floor(rand((player.str + player.inte) / 20));
			}
			else if (flags[progress] == 3) {
				outputText("With the " + buildingDesc + " now reduced to a pile of debris, you can focus on grabbing anything of use. The stone bricks are in a decent condition, even after all the trauma they could still be reclaimed for use in your construction projects. You take out your chisel and strike it with your hammer to chip away at the remaining mortar. It doesn’t take a lot of effort as the bricks easily fall apart into usable pieces. You sort the stone bricks into a neat pile on a pallet; the process taking you the better half of an hour. You tie the bricks together to secure them and take a final look at what was once a " + buildingDesc + ", now completely stripped down to the foundation. You leave behind the barren plot and haul the pile of stone bricks to your camp.");
				stones = 5 + rand(5) + Math.floor(rand((player.str + player.inte) / 12));
			}
			//Add to resources and display text.
			player.addKeyValue("Carpenter's Toolbox", 1, nails);
			flags[kFLAGS.CAMP_CABIN_WOOD_RESOURCES] += wood;
			flags[kFLAGS.CAMP_CABIN_STONE_RESOURCES] += stones;

			if (nails > 0) resourceGainText.push("" + nails + (nails == 1 ? " nail" : " nails"));
			if (wood > 0) resourceGainText.push(wood + " wood");
			if (stones > 0) resourceGainText.push("" + stones + (stones == 1 ? " stone" : " stones"));

			if (nails + wood + stones > 0) outputText("\n\nYou have scavenged " + formatStringArray(resourceGainText) + "!");

			flags[progress]++; //Increment progress and clear furniture found variable, if any.
			if (progress == 4) outputText("\n\nThe " + buildingDesc + " you had been focusing on dismantling and scavenging has been completely stripped down to the foundation.");
			if (progress == kFLAGS.TOWN_RUINS_HOUSE_SCAVENGE_PROGRESS && flags[kFLAGS.TOWN_RUINS_HOUSES_DISMANTLED] < 10 && flags[progress] >= 4) {
				flags[progress] = 0;
				flags[kFLAGS.TOWN_RUINS_HOUSES_DISMANTLED]++;
				flags[kFLAGS.TOWN_RUINS_HOUSE_FURNITURE_FOUND] = 0;
			}
			furnitureFoundToday = "";
			doNext(camp.returnToCampUseOneHour);
		}

		private function findFurniture(building:String = "house"):void { //Find furniture? Lucky!
			if (furnitureFoundToday != "") return;
			var choice:Array = [];
			var select:int;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_BED] == 0 && building == "house") choice[choice.length] = 0;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_NIGHTSTAND] == 0 && building == "house") choice[choice.length] = 1;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER] == 0 && building == "house") choice[choice.length] = 2;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_TABLE] == 0) choice[choice.length] = 3;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_CHAIR1] == 0 || flags[kFLAGS.CAMP_CABIN_FURNITURE_CHAIR2] == 0 || flags[kFLAGS.CAMP_CABIN_FURNITURE_DESKCHAIR]) choice[choice.length] = 4;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_BOOKSHELF] == 0) choice[choice.length] = 5;
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_DESK] == 0) choice[choice.length] = 6;
			select = choice[rand(choice.length)];
			switch(select) {
				case 0: outputText("\n\nMoving around the debris inside of the house you find a bed! Thinking you'll finally have something other than your old sleep roll to lay on gives you a sense of hope, which is quickly shattered when you find the actual mattress. It's covered in ash and some wh... Oh that's... Well, you aren't going to sleep on that, but the bed frame itself still seems usable and untainted.");
						outputText("\n\nAfter carefully removing the gross mattress, the bed frame seems to be made from nicely carved wood, but durability is a factor here as well so you give it a slight kick. When the frame proves resilient and unmoving you nod to yourself in approval and begin to wonder how you’re going to lug this back to camp...");
						furnitureFoundToday = "bed";
						flags[kFLAGS.CAMP_CABIN_FURNITURE_BED] = 1; break;
				case 1: outputText("\n\nLooking around the interior you move a broken piece of wood and find a drawer under it that must belong to a nightstand; useless without the actual stand, though. You put it down in a corner and go back to scavenging until you find another! Two drawers for one stand. This might actually be usable if you could just find the stand... Sifting through the larger piles of debris you find something that looks to be a hollow box with a carved design around it, maybe this is it?");
						outputText("\n\nYou find the drawers easily and slide them in; they fit perfectly, showing off the neat design of the piece and rolling out easily. Overall it seems undamaged, what a lucky find! Now, how to get this back to camp...");
						furnitureFoundToday = "nightstand";
						flags[kFLAGS.CAMP_CABIN_FURNITURE_NIGHTSTAND] = 1; break;
				case 2: outputText("Looking around the interior you move a broken piece of wood and find a wide drawer under it that must belong to a dresser; useless without the actual dresser, though. You put it down in a corner and go back to scavenging until you find another! And another. And yet another. Four drawers for one dresser. This might actually be usable if you could just find the stand... Sifting through the larger piles of debris you find something that looks to be a wide hollow box with a carved design around it, maybe this is it?");
						outputText("\n\nYou find the drawers easily and slide them in; they fit perfectly, showing off the neat design of the piece and rolling out easily. There are no missing drawers. Overall it seems undamaged, what a lucky find! Now, how to get this back to camp...");
						furnitureFoundToday = "dresser";
						flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER] = 1; break;
				case 3: outputText("\n\nThere is a table that’s surprisingly intact. It looks large enough to be accompanied by two chairs but none are seen within the vicinity. Giving the table an experimental shake you confirm that the table is stable and in usable condition.");
						furnitureFoundToday = "table";
						flags[kFLAGS.CAMP_CABIN_FURNITURE_TABLE] = 1; break;
				case 4: outputText("\n\nYou find a toppled over chair amidst the debris of the house; it’s finely carved from wood, and doesn't look too damaged. You give it an experimental sit to test its stability. The chair withstands the test and seems to have kept its strength through the wear of time.");
						furnitureFoundToday = "chair";
						if (flags[kFLAGS.CAMP_CABIN_FURNITURE_CHAIR2] > 0) flags[kFLAGS.CAMP_CABIN_FURNITURE_DESKCHAIR] = 1;
						else if (flags[kFLAGS.CAMP_CABIN_FURNITURE_CHAIR1] > 0) flags[kFLAGS.CAMP_CABIN_FURNITURE_CHAIR2] = 1;
						else flags[kFLAGS.CAMP_CABIN_FURNITURE_CHAIR1] = 1; break;
				case 5: outputText("\n\nMoving some debris from a wall something topples over and nearly catches you under it! You manage to step back before it falls and see it's a bookshelf. It seems surprisingly intact, although not as much can be said for the few books that lay within it, all but one charred by fire. With an air of curiosity, you pick up and open it, flipping through the pages that are... stained with demon spunk. Is nothing sacred? You haul up the bookshelf and roughly shake out the contents, spilling them to mix with the debris already filling the room. You move the bookcase outside and take a good look at it. It's hand carved and made of durable wood, as your rough handling proved earlier.");
						outputText("\n\nNow that you think of it, you could always use a bookshelf back at camp...");
						furnitureFoundToday = "bookshelf";
						flags[kFLAGS.CAMP_CABIN_FURNITURE_BOOKSHELF] = 1; break;
				case 6: outputText("\n\nWhile you're moving a particularly large bit of debris you notice it's actually a desk, and a rather nice one at that! Quickly checking it over, it looks finely carved and made of sturdy wood, and a few knocks in certain areas confirms it. This desk is still in pretty good condition and could be used at your camp, now it's just a matter of how to get it there...");
						furnitureFoundToday = "desk";
						flags[kFLAGS.CAMP_CABIN_FURNITURE_DESK] = 1; break;
				default:outputText("\n\nYou continue to search thoroughly but despite that, you fail to find anything useful."); //Failsafe
						furnitureFoundToday = "null";
			}
			if (furnitureFoundToday != "null") {
				outputText("\n\n");
				if (flags[kFLAGS.CAMP_CABIN_PROGRESS] >= 10) outputText("This would be a great addition to your cabin. ");
				outputText("You haul the " + furnitureFoundToday + " outside the " + building + ", sitting it down in sight but away from the " + building + ". Ready to be hauled back to camp when you're done here.");
			}
		}
	}

}


code:
package classes.Scenes
{
	import classes.*;
	import classes.GlobalFlags.*;
	import classes.Items.ArmorLib;
	import classes.internals.PregnancyUtils;
	import flash.utils.Dictionary;
	import classes.internals.LoggerFactory;
	import mx.logging.ILogger;

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

		/**
		 * This sensing variable is used by tests to detect if
		 * the vaginal birth code has been called. This is used for pregnancies
		 * that do not provide any other means of detection (e.g. counter variables).
		 */
		public var senseVaginalBirth:Vector.<int>;

		/**
		 * This sensing variable is used by tests to detect if
		 * the anal birth code has been called. This is used for pregnancies
		 * that do not provide any other means of detection (e.g. counter variables).
		 */
		public var senseAnalBirth:Vector.<int>;

		/**
		 * Map pregnancy type to the class that contains the matching scenes.
		 * Currently only stores player pregnancies.
		 */
		private var vaginalPregnancyScenes:Dictionary;

		/**
		 * Map pregnancy type to the class that contains the matching scenes.
		 * Currently only stores player pregnancies.
		 */
		private var analPregnancyScenes:Dictionary;

		public function PregnancyProgression() {
			this.senseVaginalBirth = new Vector.<int>();
			this.senseAnalBirth = new Vector.<int>();

			this.vaginalPregnancyScenes = new Dictionary();
			this.analPregnancyScenes = new Dictionary();
		}

		/**
		 * Record a call to a vaginal birth function.
		 * This method is used for testing.
		 * @param	pregnancyType to record
		 */
		public function detectVaginalBirth(pregnancyType:int):void {
			senseVaginalBirth.push(pregnancyType);
		}

		/**
		 * Record a call to a anal birth function.
		 * This method is used for testing.
		 * @param	pregnancyType to record
		 */
		public function detectAnalBirth(pregnancyType:int):void
		{
			senseAnalBirth.push(pregnancyType);
		}

		/**
		 * Register a scene for vaginal pregnancy. The registered scene will be used for pregnancy
		 * progression and birth.
		 * Note: Currently only the player is supported as the mother.
		 *
		 * @param	pregnancyTypeMother The creature that is the mother
		 * @param	pregnancyTypeFather The creature that is the father
		 * @param	scenes The scene to register for the combination
		 * @return true if an existing scene was overwritten
		 * @throws ArgumentError If the mother is not the player
		 */
		public function registerVaginalPregnancyScene(pregnancyTypeMother:int, pregnancyTypeFather:int, scenes:VaginalPregnancy):Boolean {
			if (pregnancyTypeMother !== PregnancyStore.PREGNANCY_PLAYER) {
				LOGGER.error("Currently only the player is supported as mother");
				throw new ArgumentError("Currently only the player is supported as mother");
			}

			var previousReplaced:Boolean = false;

			if (hasRegisteredVaginalScene(pregnancyTypeMother, pregnancyTypeFather)) {
				previousReplaced = true;
				LOGGER.warn("Vaginal scene registration for mother {0}, father {1} will be replaced.", pregnancyTypeMother, pregnancyTypeFather);
			}

			vaginalPregnancyScenes[pregnancyTypeFather] = scenes;
			LOGGER.debug("Mapped pregancy scene {0} to mother {1}, father {2}", scenes, pregnancyTypeMother, pregnancyTypeFather);

			return previousReplaced;
		}

		/**
		 * Register a scene for anal pregnancy. The registered scene will be used for pregnancy
		 * progression and birth.
		 * Note: Currently only the player is supported as the mother.
		 *
		 * @param	pregnancyTypeMother The creature that is the mother
		 * @param	pregnancyTypeFather The creature that is the father
		 * @param	scenes The scene to register for the combination
		 * @return true if an existing scene was overwritten
		 * @throws ArgumentError If the mother is not the player
		 */
		public function registerAnalPregnancyScene(pregnancyTypeMother:int, pregnancyTypeFather:int, scenes:AnalPregnancy):Boolean
		{
			if (pregnancyTypeMother !== PregnancyStore.PREGNANCY_PLAYER) {
				LOGGER.error("Currently only the player is supported as mother");
				throw new ArgumentError("Currently only the player is supported as mother");
			}

			var previousReplaced:Boolean = false;

			if (hasRegisteredAnalScene(pregnancyTypeMother, pregnancyTypeFather)) {
				previousReplaced = true;
				LOGGER.warn("Anal scene registration for mother {0}, father {1} will be replaced.", pregnancyTypeMother, pregnancyTypeFather);
			}

			analPregnancyScenes[pregnancyTypeFather] = scenes;
			LOGGER.debug("Mapped anal pregancy scene {0} to mother {1}, father {2}", scenes, pregnancyTypeMother, pregnancyTypeFather);

			return previousReplaced;
		}

		/**
		 * Check if the given vaginal pregnancy combination has a registered scene.
		 * @param	pregnancyTypeMother The creature that is the mother
		 * @param	pregnancyTypeFather The creature that is the father
		 * @return true if a scene is registered for the combination
		 */
		public function hasRegisteredVaginalScene(pregnancyTypeMother:int, pregnancyTypeFather:int):Boolean {
			// currently only player pregnancies are supported
			if (pregnancyTypeMother !== PregnancyStore.PREGNANCY_PLAYER) {
				return false;
			}

			return pregnancyTypeFather in vaginalPregnancyScenes;
		}

		/**
		 * Check if the given anal pregnancy combination has a registered scene.
		 * @param	pregnancyTypeMother The creature that is the mother
		 * @param	pregnancyTypeFather The creature that is the father
		 * @return true if a scene is registered for the combination
		 */
		public function hasRegisteredAnalScene(pregnancyTypeMother:int, pregnancyTypeFather:int):Boolean
		{
			// currently only player pregnancies are supported
			if (pregnancyTypeMother !== PregnancyStore.PREGNANCY_PLAYER) {
				return false;
			}

			return pregnancyTypeFather in analPregnancyScenes;
		}

		/**
		 * Update the current vaginal and anal pregnancies (if any). Updates player status and outputs messages related to pregnancy or birth.
		 * @return true if the output needs to be updated
		 */
		public function updatePregnancy():Boolean
		{
			var displayedUpdate:Boolean = false;
			var pregText:String = "";
			if ((player.pregnancyIncubation <= 0 && player.buttPregnancyIncubation <= 0) ||
				(player.pregnancyType === 0 && player.buttPregnancyType === 0)) {
				return false;
			}

			displayedUpdate = cancelHeat();

			if (player.pregnancyIncubation > 0 && player.pregnancyIncubation < 2) player.knockUpForce(player.pregnancyType, 1);
			//IF INCUBATION IS VAGINAL
			if (player.pregnancyIncubation > 1) {
				displayedUpdate = updateVaginalPregnancy(displayedUpdate);
			}
			//IF INCUBATION IS ANAL
			if (player.buttPregnancyIncubation > 1) {
				displayedUpdate = updateAnalPregnancy(displayedUpdate);
			}

			amilyPregnancyFailsafe();

			if (player.pregnancyIncubation === 1) {
				displayedUpdate = updateVaginalBirth(displayedUpdate);
			}

			if (player.buttPregnancyIncubation === 1) {
				displayedUpdate = updateAnalBirth(displayedUpdate);
			}

			return displayedUpdate;
		}

		private function cancelHeat():Boolean
		{
			if (player.inHeat) {
				outputText("\nYou calm down a bit and realize you no longer fantasize about getting fucked constantly.  It seems your heat has ended.\n");
				//Remove bonus libido from heat
				dynStats("lib", -player.statusEffectv2(StatusEffects.Heat));

				if (player.lib < 10) {
					player.lib = 10;
				}

				statScreenRefresh();
				player.removeStatusEffect(StatusEffects.Heat);

				return true;
			}

			return false;
		}

		private function updateVaginalPregnancy(displayedUpdate:Boolean):Boolean
		{
			if (hasRegisteredVaginalScene(PregnancyStore.PREGNANCY_PLAYER, player.pregnancyType)) {
				var scene:VaginalPregnancy = vaginalPregnancyScenes[player.pregnancyType] as VaginalPregnancy;
				LOGGER.debug("Updating pregnancy for mother {0}, father {1} by using class {2}", PregnancyStore.PREGNANCY_PLAYER, player.pregnancyType, scene);
				return scene.updateVaginalPregnancy();
			} else {
				LOGGER.debug("Could not find a mapped vaginal pregnancy for mother {0}, father {1} - using legacy pregnancy progression", PregnancyStore.PREGNANCY_PLAYER, player.pregnancyType);;
			}

			return displayedUpdate;
		}

		private function updateAnalPregnancy(displayedUpdate:Boolean):Boolean
		{
			var analPregnancyType:int = player.buttPregnancyType;

			if (hasRegisteredAnalScene(PregnancyStore.PREGNANCY_PLAYER, analPregnancyType)) {
				var scene:AnalPregnancy = analPregnancyScenes[analPregnancyType] as AnalPregnancy;
				LOGGER.debug("Updating anal pregnancy for mother {0}, father {1} by using class {2}", PregnancyStore.PREGNANCY_PLAYER, analPregnancyType, scene);
				return scene.updateAnalPregnancy() || displayedUpdate;
			} else {
				LOGGER.debug("Could not find a mapped anal pregnancy for mother {0}, father {1} - using legacy pregnancy progression", PregnancyStore.PREGNANCY_PLAYER, analPregnancyType);
			}

			return displayedUpdate;
		}

		/**
		 * Changes pregnancy type to Mouse if Amily is in a invalid state.
		 */
		private function amilyPregnancyFailsafe():void
		{
			//Amily failsafe - converts PC with pure babies to mouse babies if Amily is corrupted
			if (player.pregnancyIncubation === 1 && player.pregnancyType === PregnancyStore.PREGNANCY_AMILY)
			{
				if (flags[kFLAGS.AMILY_FOLLOWER] === 2 || flags[kFLAGS.AMILY_CORRUPTION] > 0) {
					player.knockUpForce(PregnancyStore.PREGNANCY_MOUSE, player.pregnancyIncubation);
				}
			}

			//Amily failsafe - converts PC with pure babies to mouse babies if Amily is with Urta
			if (player.pregnancyIncubation === 1 && player.pregnancyType === PregnancyStore.PREGNANCY_AMILY)
			{
				if (flags[kFLAGS.AMILY_VISITING_URTA] === 1 || flags[kFLAGS.AMILY_VISITING_URTA] === 2) {
					player.knockUpForce(PregnancyStore.PREGNANCY_MOUSE, player.pregnancyIncubation);
				}
			}

			//Amily failsafe - converts PC with pure babies to mouse babies if PC is in prison.
			if (player.pregnancyIncubation === 1 && player.pregnancyType === PregnancyStore.PREGNANCY_AMILY)
			{
				if (prison.inPrison) {
					player.knockUpForce(PregnancyStore.PREGNANCY_MOUSE, player.pregnancyIncubation);
				}
			}
		}

		/**
		 * Check is the player has a vagina and create one if missing.
		 */
		private function createVaginaIfMissing(): void {
			PregnancyUtils.createVaginaIfMissing(output, player);
		}

		private function updateVaginalBirth(displayedUpdate:Boolean):Boolean
		{
			if (hasRegisteredVaginalScene(PregnancyStore.PREGNANCY_PLAYER, player.pregnancyType)) {
				var scene:VaginalPregnancy = vaginalPregnancyScenes[player.pregnancyType] as VaginalPregnancy;
				LOGGER.debug("Updating vaginal birth for mother {0}, father {1} by using class {2}", PregnancyStore.PREGNANCY_PLAYER, player.pregnancyType, scene);
				scene.vaginalBirth();

				// TODO find a cleaner way to solve this
				// ignores Benoit pregnancy because that is a special case
				if (player.pregnancyType !== PregnancyStore.PREGNANCY_BENOIT) {
					giveBirth();
				}
			} else {
				LOGGER.debug("Could not find a mapped vaginal pregnancy scene for mother {0}, father {1} - using legacy pregnancy progression", PregnancyStore.PREGNANCY_PLAYER, player.pregnancyType);;
			}

			// TODO find a better way to do this
			// due to non-conforming pregancy code
			if (player.pregnancyType === PregnancyStore.PREGNANCY_BENOIT && player.pregnancyIncubation === 3) {
				return displayedUpdate;
			}

			player.knockUpForce();

			return true;
		}

		/**
		 * Updates fertility and tracks number of births. If the player has birthed
		 * enough children, gain the broodmother perk.
		 */
		public function giveBirth():void
		{
			//TODO remove this once new Player calls have been removed
			var player:Player = game.player;

			if (player.fertility < 15) {
				player.fertility++;
			}

			if (player.fertility < 25) {
				player.fertility++;
			}

			if (player.fertility < 40) {
				player.fertility++;
			}

			if (!player.hasStatusEffect(StatusEffects.Birthed)) {
				player.createStatusEffect(StatusEffects.Birthed,1,0,0,0);
			} else {
				player.addStatusValue(StatusEffects.Birthed,1,1);

				if (player.findPerk(PerkLib.BroodMother) < 0 && player.statusEffectv1(StatusEffects.Birthed) >= 10) {
					output.text("\nYou have gained the Brood Mother perk (Pregnancies progress twice as fast as a normal woman's).\n");
					player.createPerk(PerkLib.BroodMother,0,0,0,0);
				}
			}
		}

		private function updateAnalBirth(displayedUpdate:Boolean):Boolean
		{
			var analPregnancyType:int = player.buttPregnancyType;

			if (hasRegisteredAnalScene(PregnancyStore.PREGNANCY_PLAYER, analPregnancyType)) {
				var scene:AnalPregnancy = analPregnancyScenes[analPregnancyType] as AnalPregnancy;
				LOGGER.debug("Updating anal birth for mother {0}, father {1} by using class {2}", PregnancyStore.PREGNANCY_PLAYER, analPregnancyType, scene);
				scene.analBirth();
				displayedUpdate = true;
			} else {
				LOGGER.debug("Could not find a mapped anal pregnancy scene for mother {0}, father {1} - using legacy pregnancy progression", PregnancyStore.PREGNANCY_PLAYER, analPregnancyType);
			}

			player.buttKnockUpForce();
			return displayedUpdate;
		}
	}
}


code:
package classes.Scenes.Quests.UrtaQuest
{
	import classes.*;
	import classes.BodyParts.*;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.Scenes.Monsters.AbstractSuccubus;
	import classes.internals.*;

	use namespace kGAMECLASS;

	public class MilkySuccubus extends AbstractSuccubus
	{

		override protected function performCombatAction():void
		{
			var actionChoices:MonsterAI = new MonsterAI();
			actionChoices.add(cowCubiMilkSprayAttack, 0.3, !hasStatusEffect(StatusEffects.MilkyUrta), 10, FATIGUE_MAGICAL, RANGE_RANGED);
			actionChoices.add(drinkMinoCum, 2, HP < 400, 0, FATIGUE_NONE, RANGE_SELF);
			actionChoices.add(eAttack, 1, player.HP < 100, 0, FATIGUE_NONE, RANGE_MELEE);
			actionChoices.add(succubusTease, 1, player.lust100 >= 90, 0, FATIGUE_NONE, RANGE_TEASE);
			actionChoices.add(eAttack, 1, true, 0, FATIGUE_NONE, RANGE_MELEE);
			actionChoices.exec();
		}

		private function cowCubiMilkSprayAttack():void
		{
			//Lasts a couple turns like the goblin lust poison?
			outputText("\"How about a taste?\"  The succubus asks, pressing her tits together.  Before you can reply, a veritable jet of milk sprays in your direction!\n");
//Miss:
			if (rand(20) + 1 + player.spe / 20 > 17) {
				outputText("With your trained reflexes, you manage to duck and roll, narrowly avoiding getting sprayed with milk.");
				outputText("\n\n\"Such a waste.\"  The succubus pouts.  \"No worries, I'll just have Fido clean it up later... perhaps I'll even have you do it later, when you become mine.\"  The succubus giggles.");
				game.dynStats("lus", 6);
			}
			//Hit:
			else {
				outputText("All you manage to do is cover your face; the rest of you, however, gets completely soaked in the demon's corrupted milk.  Looking down at yourself, you realize that you are panting, and the places where the milk splashed your " + (game.noFur() ? "skin" : "fur") + " begin to heat up.  Oh no! You'd better finish off this succubus before you succumb to your lusts!");
				game.dynStats("lus", 15);
				createStatusEffect(StatusEffects.MilkyUrta, 3, 0, 0, 0);
			}

		}

		private function drinkMinoCum():void
		{
			outputText("Smiling wryly and licking her lips, the succubus-cow procures a bottle of her pet's cum with her probing tail.");
//Success:
			if (!hasStatusEffect(StatusEffects.DrankMinoCum) || !hasStatusEffect(StatusEffects.DrankMinoCum2)) {
				outputText("\n\nSmiling triumphantly, she takes the bottle and opens it with a pop, drinking the contents with glee.  When done, she throws the bottle away and smacks her lips.  \"Nothing like a bottle of minotaur cum to get you back on your feet, right?\"  She grins, her pussy dripping with more juices.");
				addHP(400);
				lust += 25;
				if (!hasStatusEffect(StatusEffects.DrankMinoCum)) createStatusEffect(StatusEffects.DrankMinoCum, 0, 0, 0, 0);
				else createStatusEffect(StatusEffects.DrankMinoCum2, 0, 0, 0, 0);
			}
			//Failure:
			else {
				outputText("\n\nShe frowns and looks behind her, pouting slightly when she turns to look back at you.  \"Seems like I'm all out of cum.\"  She grins evilly.  \"I'll just have to get more after I'm done with you.\"");
			}

		}

		private function succubusTease():void
		{
			if (rand(4) == 0) outputText("Turning around, the succubus begins to bounce her rather round derriere in your direction, the cheeks lewdly clapping together with each change in direction, exposing her dark anal star and juicy snatch, literally gushing forth a stream of lubricants.  Her eyes glow with faint, purple light as she whispers, \"Don't you just want to... slide on in?\"");
			else if (rand(3) == 0) outputText("The succubus squeezes her spotted, sweat-oiled breasts together, squirting out trickles of fresh, creamy, succubi milk.  Bending down, she laps at her own bounty, taking to meet your eyes, her own glowing violet.  You can feel her next words as much as hear them, reaching into your brain and stirring a familiar heat in your loins.  \"Giving in would mean pleasure unending, my dear vixen.\"");
			else if (rand(2) == 0) outputText("The succubus turns slightly and slowly bends over, sliding her hands down the sides of her milk laden jugs. \"Mmm, would you help a poor girl relax? These things need some attention,\" she says with a lust filled moan as her hands reach her multitude of nipples.");
			else outputText("The succubus leans forwards holding her tits, while wrapping her fingers around her nipples.  \"My boobs are soo full.  Would you like to help me drain them?\" she says with a husky voice.");
			game.dynStats("lus", 20);

		}

		override public function defeated(hpVictory:Boolean):void
		{
			game.urtaQuest.urtaBeatsUpCowcubi();
		}

		override public function won(hpVictory:Boolean, pcCameWorms:Boolean = false):void
		{
			game.urtaQuest.urtaLosesToCowCubi();
		}

		override public function teased(lustDelta:Number):void
		{
			outputText(capitalA + short + " smiles, rubbing her hands across herself as she watches your display.  She does not seem greatly affected by your show - at least in the sense of increasing arousal.  She does seem oddly more... vital, as if she drew strength from the very display you put on.");
			str += 5;
			addHP(50);
			applyTease(lustDelta);
		}

		public function MilkySuccubus()
		{
			this.a = "the ";
			this.short = "milky succubus";
			this.imageName = "milkysuccubus";
			this.long = "You are fighting a milky, cow-like succubus.  She stands about seven feet tall and is hugely voluptuous, with breasts three times the size of her head, tipped with a cluster of four obscenely teat-like nipples.  Her hips flare out into an exaggerated hourglass shape, with a long tail tipped with a fleshy arrow-head spade that waves above her spankable butt.  A small cowbell is tied at the base of the arrow-head with a cute little ribbon.  Wide, cow-like horns, easily appropriate for a minotaur, rise from her head, and she flicks bovine ears about the sides of her head whilst sashaying from side to side on demonic, high-heeled feet.  Her skin is a vibrant purple with splotches of shiny black here and there, including one large spot covering her right eye.  She's using a leather whip as a weapon.";
			this.race = "Demon";
			// this.plural = false;
			this.createVagina(false, Vagina.WETNESS_SLAVERING, Vagina.LOOSENESS_NORMAL);
			this.createStatusEffect(StatusEffects.BonusVCapacity, 300, 0, 0, 0);
			createBreastRow(Appearance.breastCupInverse("G"));
			this.ass.analLooseness = Ass.LOOSENESS_STRETCHED;
			this.ass.analWetness = Ass.WETNESS_SLIME_DROOLING;
			this.tallness = 84;
			this.hips.rating = Hips.RATING_CURVY;
			this.butt.rating = Butt.RATING_LARGE+1;
			this.lowerBody.type= LowerBody.DEMONIC_HIGH_HEELS;
			this.skin.tone = "blue";
			this.hair.color = "black";
			this.hair.length = 13;
			initStrTouSpeInte(75, 50, 125, 95);
			initLibSensCor(90, 60, 99);
			this.weaponName = "whip";
			this.weaponVerb="whipping";
			this.weaponAttack = 10;
			this.weaponPerk = [];
			this.weaponValue = 150;
			this.armorName = "demonic skin";
			this.armorDef = 10;
			this.bonusHP = 700;
			this.lust = 40;
			this.lustVuln = .3;
			this.temperment = TEMPERMENT_LOVE_GRAPPLES;
			this.level = 16;
			this.gems = rand(25) +10;
			this.additionalXP = 50;
			this.drop = NO_DROP;
			this.horns.type = Horns.DRACONIC_X2;
			this.horns.value = 2;
			this.wings.type = Wings.BAT_LIKE_TINY;
			this.tail.type = Tail.DEMONIC;
			this.special1 = kissAttack;
			this.special2 = seduceAttack;
			this.special3 = whipAttack;
			this.drop = NO_DROP;
			checkMonster();
		}

	}

}


code:
package classes.Scenes.Quests.UrtaQuest
{
	import classes.*;
	import classes.BodyParts.*;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.Scenes.Areas.Desert.Naga;
	import classes.internals.*;

	public class Sirius extends Naga
	{

		override public function eAttack():void
		{
			outputText("Sirius readies his hands, undulating his body erratically with quick motions in order to catch you off-guard and strike at you.\n");
			super.eAttack();
		}

		override protected function outputPlayerDodged(dodge:int):void
		{
			outputText("With your trained eyes, you see through his feints and effectively block his first swipe, then quickly twist your body to kick him away.  He clutches his belly where you kicked him, but recovers quickly, eyes fixated on yours.\n");
		}

		override public function outputAttack(damage:int):void
		{
			if (damage<=0) {
				super.outputAttack(damage);
			} else {
				outputText("You misjudge his pattern and wind up getting slashed by a series of swipes from his sharpened nails.  He distances himself from you in order to avoid retaliation and glares at you with his piercing yellow eyes, a hint of a smile on his face. (" + damage + ")");
			}
		}

		override protected function performCombatAction():void
		{
			var actionChoices:MonsterAI = new MonsterAI();
			actionChoices.add(eAttack, 1, true, 0, FATIGUE_NONE, RANGE_MELEE);
			actionChoices.add(poisonBite, 1, true, 10, FATIGUE_PHYSICAL, RANGE_MELEE_CHARGING);
			actionChoices.add(manNagaTease, 1, true, 0, FATIGUE_NONE, RANGE_TEASE);
			actionChoices.add(nagaSpitAttack, 1, player.hasStatusEffect(StatusEffects.Blind), 10, FATIGUE_PHYSICAL, RANGE_RANGED);
			actionChoices.exec();

		}

		private function manNagaTease():void
		{
			outputText("The snake-man stares deeply into your eyes, seemingly looking past them, and for a moment your body goes numb.");
//Miss:
			if (rand(10) == 0) {
				outputText("  You blink and shake yourself free of the effects of the snake-man's penetrating gaze.");

			}
//Hit (Blind):
			if (hasStatusEffect(StatusEffects.Blind)) {
				outputText("  Though your vision is still blurry, you feel yourself being sucked into the golden depths of those pupils, making you forget all your worries, if only for an instant.  All you can focus on is your growing arousal as you sink deeper into his gaze.  You shake your head, clearing your mind of the hypnotising effects the snake-man's eyes seem to possess, though the arousal remains.");
				game.dynStats("lus", (5 + player.lib / 10 - player.inte / 20));
			}
			//Hit:
			else {
				outputText("  Those pools of yellow suck you into their golden depths, making you forget all your worries, if only for an instant.  All you can focus on is your growing arousal as you sink deeper into his gaze.  You shake your head, clearing your mind of the hypnotising effects the snake-man's eyes seem to possess, though the arousal remains.");
				game.dynStats("lus", (10 + player.lib / 7 - player.inte / 20));
			}

		}

		private function nagaSpitAttack():void
		{
			outputText("Hissing loudly, Sirius suddenly curls his lips and spits at your eyes!  ");
//{Hit:
			if (spe / 20 + rand(20) + 1 > player.spe / 20 + 10) {
				outputText("The vile spray hits your eyes and you scream in pain, clawing fiercely at your burning, watering, weeping eyes.  You can't see!  It'll be much harder to fight in this state, but at the same time, his hypnosis won't be so effective...");
				player.createStatusEffect(StatusEffects.Blind, 3, 0, 0, 0);
			}
			//Miss:
			else outputText("You quickly lean to the side, narrowly avoiding being blinded by the snake-man's spit!");

		}

		private function poisonBite():void
		{
			outputText("With a loud and vicious hiss, Sirius suddenly lunges at you, mouth distended impossibly wide and revealing four needle-like fangs dripping with venom!  ");
//Miss:
			if (!combatAvoidDamage({doDodge:true,doParry:false,doBlock:false}).failed) {
				outputText("You dodge just in the nick of time, and deliver a punishing blow with the butt of your halberd as Sirius soars past, forcing him to slither past you to make himself ready to defend himself again.");

			}
//Hit:
			outputText("The snake-man moves too quickly for you to evade and he sinks long fangs into your flesh, leaving a wound that burns with horrific pain. ");
			var damage:Number = 40 + rand(20);
			damage = player.takeDamage(damage, true);

		}

		override public function defeated(hpVictory:Boolean):void
		{
			game.urtaQuest.urtaBeatsUpSiriusRadio();
		}

		override public function won(hpVictory:Boolean,pcCameWorms:Boolean = false):void
		{
			game.urtaQuest.urtaLosesToSirriusSnakeRadio();
		}

		public function Sirius()
		{
			super(true);
			this.a = "";
			this.short = "Sirius, a naga hypnotist";
			this.imageName = "sirius";
			this.long = "A strange being with the upper torso of a human man topped with the head of a giant serpent stands before you, hissing in anger and occasionally letting a long, fork-tipped tongue flicker out past his lips.  An imperial-featured masculine human face regards you with an indifferent expression.  A ponytail of deep orange - almost bright red - hair falls down between his shoulders, held together by snake-styled circlets of silver, and matching bracelets of the same material and design adorn his wrists. Scales begin at his lower waist, concealing his manhood from you; he's completely naked otherwise.  His snake body is long and slender, covered in finely meshing scales of a rich orange-red shade, the red broken by a pattern of randomly thick or thin stripes of black.  His burning yellow eyes stare directly into yours, vertical slits of pupils fixated on your own as he undulates and coils in an eerily seductive manner.";
			this.race = "Naga";
			this.plural = false;
			this.createCock(14,2);
			createBreastRow(0);
			this.ass.analLooseness = Ass.LOOSENESS_TIGHT;
			this.ass.analWetness = Ass.WETNESS_DRY;
			this.createStatusEffect(StatusEffects.BonusACapacity,10,0,0,0);
			this.tallness = 5*12+10;
			this.hips.rating = Hips.RATING_AMPLE+2;
			this.butt.rating = Butt.RATING_LARGE;
			this.lowerBody.type= LowerBody.NAGA;
			this.skin.tone = "mediterranean-toned";
			this.hair.color = "orange";
			this.hair.length = 16;
			initStrTouSpeInte(75, 70, 75, 92);
			initLibSensCor(45, 35, 40);
			this.weaponName = "fangs";
			this.weaponVerb="bite";
			this.weaponAttack = 25;
			this.armorName = "scales";
			this.armorDef = 30;
			this.bonusHP = 400;
			this.lust = 30;
			this.temperment = TEMPERMENT_RANDOM_GRAPPLES;
			this.level = 12;
			this.gems = rand(5) + 8;
			this.drop = NO_DROP;
			this.special1 = nagaPoisonBiteAttack;
			this.special2 = nagaConstrict;
			this.special3 = nagaTailWhip;
			checkMonster();
		}

	}

}


code:
How to work with refactored Scenes, Monsters, and Items?
==============================================================

# Monster classes

`Monster` class represents something player combats with. Its fields are combat params, its methods are attacks and AI.

## Creating new monster

### Basics

Go to Monster constructor, copy its contents, uncomment, and follow the instructions.
There is a number of fields that **MUST** be initialized. If you miss them, you will get a **/!\\BUG** message during
 the combat.

The resulting monster will have a default AI (which is randomly choose between physical attack or one of specials),
will not have any victory/loss rape scenes (but still will drop gems and xp / take gems and 8 hours).

To start the combat with that monster in the scene, just call `startCombat(new MyMonster());`. You can also assign
monster to a variable and modify it.

You also should add the monster to `Scenes/Explore/ExploreDebug.allMonsters` array, so it will be combated in that debug
scene. You can put it in the beginning of the array to quicky test it in debug mode. In that test also check the
inspection and compare it with description.

### Special attacks

Default monsters can have up to 3 special attacks stored in fields `special1`, `special2`, `special3`.
Values could be either 5xxx event codes (old-style, use **ONLY** for existing special) or function references.

Any special attack at all the return points should call `combatRoundOver()` to mark end of monster action.

### Scenes: approach, defeated, won

You might want to write a special Scene class for the monster, which will contain

* approach scene that describes how monster attacks the player and calls `startCombat(new MyMonster())`;
* player victory scene that shows victory rape options.
  Don't forget to call `cleanupAfterCombat()`, `awardPlayer()`, or `finishCombat()` in the end (after the rape/leave).
  The difference is:
    - `cleanupAfterCombat()` calls `awardPlayer()`.
    - `finishCombat()` displays _"You defeat..."_ message and calls `awardPlayer()`.
    - `awardPlayer()` gives player XP and gems, displays messages about it, and resets `gameState` to 0.
* monster victory scene when player is defeated and raped by monster.
  Don't forget to call `cleanupAfterCombat()` in the end (after the rape).

### Overriding AI

To better understand which function to override for monster behaviour customization, here combat call flow is shown:

1. Player selects some combat action (`event 5000`).
2. `enemyAI()` is called, which just contains call to...
    1. `monster.doAI()`, and this method could be overriden. By default:
    2. If monster is stunned, frightened, constricted or otherwise has chance to skip its turn, `monster.handleStun()`,
         `handleFear()`, `handleConstricted()` methods are called. If they `return true`, said effect is ignored.
         1. Their default implementations just
            * display messages like _"your foe is stunned"_ etc;
            * decrease statusAffect round counter by one and until it reaches zero;
            * `return false;` (skip turn).
    3. Somewhere here Exgartuan (if present) gets his chance to comment the situation by `game.exgartuan.exgartuanCombatUpdate()`
    4. From this point monster should decide its action and `Monster.performCombatAction()` (overrideable) is called.
         By default:
    5. A (evenly distributed) random action is chosen from `Monster.eAttack()` and all non-null non-zero `special`1..3.
    6. Description of `special`s was given before, supppose, `Monster.eAttack()` was called from `performCombatAction()`.
         By default:
    7. In case the monster represents a mob, `statusAffectv1(StatusAffects.attacks)` is checked for number of attacks to perform.
         For each attack:
         1. An `Monster.attackSucceeded()` is called, which by default:
            1. If monster is blind, try `Monster.handleBlind()` (`true` means continue attack). Default implementation
                of `handleBlind()` is 2/3 chance to miss and print some message.
            2. Checks `Monster.playerDodged()` which should probably reside in Player class
                1. checks and rolls for `player.speedDodge(monster)`. If `true`, `outputPlayerDodged()`,
                2. checks and rolls for player perks **"Evade"**, **"Misdirection"**, **"Flexibility"**.
         2. If `attackSucceeded()`, do damage with `eOneAttack()`, by default:
            1. Call `calcDamage()`, by default `calcDamage()=player.reduceDamage(eBaseDamage())`
                1. By default, `eBaseDamage()=str+weaponAttack`.
            2. Call `player.takeDamage(damage)`
         3. Call `outputAttack(damage)` to print how severely player is damaged
         4. Call `postAttack(damage)` to perform any post-attack effects
                (currently just raises monster lust if player wears _"barely-decent bondage straps"_).
    8. Finally, `eAttack()` removes status affect **"attacks"**, that means it should be manually set by monster AI
         each round.
    9. Finally finally if combat is not over, show _"Next"_ button.
3. Repeat steps 1-2 until combat is finished. Options are:
    1. `Monster.won()`.
    2. `Monster.defeated()`.
    3. Player flees (`gameState` is reset to 0).
    4. Game over.

#### ^^ WAS TL;DR JUST TELL ME WHAT TO OVERRIDE

See examples:

1. `Imp` for very simple monster with specials
2. `ImpLord extends Imp` for monster that uses special from other monster
3. `GoblinAssassin` for monster with >3 specials
4. `Kiha` for monster that handles fear and blind.
5. `LustyDemons` for mob of monsters with different attacks
6. `Anemone` for monster that deals non-reducable poison damage
7. `Harpy` for monster that display different message for attack blocked by player

## Monster hierarchy

Generally 99% of monsters should subclass classes.Monster directly. However there are cases when several monsters
 share special attacks etc (like male and female spider morphs, also succubi). In that case you can...

1. create abstract
 class with common methods and subclass it (see Scenes/Monsters/AbstractSuccubus and its subclasses MilkySuccubus and
 SecretarialSuccubus.
2. ...however, sometimes you have already configured monster class and you want to add a new variation (example: InfestedHellhound
 extends HellHound). In that case extracting superclass is PITA so I do that thing: I add a to superclass constructor a
 parameter like `noInit:Boolean=false` and if it is `true`, no (or partial) `initXXXX` methods are called. In subclass
 I call `super(true)` and re-init it as I want.
3. The other approach (when monster is a *very* slight modification of another) is just subclass the parent monster
 and after `super()` change some properties/fields to update it. Don't forget to a) change the name. b) to **change**
 gender, you need first call `initGenderless()` to kill the genitals created in superclass and then setup the gender.

## Monster event hooks

If you want to You can set up event hooks that replace default behaviour by setting properties in monster instance.
These hooks are:
* `monster.onWon = Function(hpVictory:Boolean,pcCameWorms:Boolean = false)` to replace monster-won code. If the field is not null,
 default behaviour is canceled, and you have to finish the combat manually.
* `monster.onDefeated = Function(hpVictory:Boolean)` to replace monster-defeated code. Same as with `onWon`.
* `monster.onPcRunAttempt = Function()` to replace various checks and possible combat end when player hits "Run".

See property docs for more details.

### Note

Event hooks should be used in scenes to modify default monsters, and not in monster classes themselves. Monster classes
should override the functions `won`, `defeated` to change behaviour from default.

# Item classes

Shortname fields and lookups are replaced with `ItemType` instances. Its members are:
* `id`: An unique across all `ItemType`s 7-character identifier that should be kept unchanged in future game versions.
* `shortName`: Currently just a copy of an `id`, but this field is intended to store very short name of the item that could be displayed on buttons instead of id.
* `longName`: Full name of an item.
* `description` A description of an item; currently used in tooltips.
* `value`: Item price.

Remember: **For each item type there should be one and only one instance of `ItemType` class with unique `id`**.
An error will be reported in `trace` if items with same `id`s are created.
`ItemType` instances are usually `const` fields of item libraries (see below).

Saving and loading are done using `id`. To get ItemType by `id`, use `ItemType.lookupItem(id:String):ItemType`.

**Every comparison "is it *that* item?" that looks like `shortName == "ThatItm"` should be
replaced with `itype == library.THATITM` where `library` is item library (see below)**.

## Class hierarchy

1. `ItemType` is superclass for every item. It could be placed into player's inventory or chest.
2. `CommonItem` contains handy methods `outputText`, `clearOutput` and a `game` property to use when performing item
   effects.
3. `Useable` has new method `useItem(player,output,external)` that **MUST** be overriden in subclasses. It is called
   whenever player uses this item, via inventory or *"Use Now"* button. To distinguish these cases, `external` property
   is added: it is `true` when item used not from player's inventory.
    1. `SimpleUseable` is `Useable` defined by constructor parameter `effect`, which is `function(player:Player):void`.
        Examples of such items are armor crafting ingredients and kitsune statue, which display text when used.
4. `Consumable` is a `Useable` that has certain requirements, whether or not it could be used; and if it could (and it is
    not `external`, it removes 1 instance of itself from `player`'s inventory. The superclass method `useItem` is already
    overrided and **MUST NOT** be overriden. Instead, `doEffect(player:Player,output:Boolean)` **MUST** be overriden;
    `canUse(player:Player,output:Boolean)` **COULD** be overriden (default: `return true`).
    1. `SimpleConsumable` is `Consumable` defined by constructor parameter `effect`, which is `function(player:Player):void`.
        \~95% of consumables are instances of `SimpleConsumables`; the rest has custom `canUse`.
5. `Equipable` is a special kind of `Consumable` that is wielded/worn by player. Special effects could be done when
    player equips/unequips `Equipable`. You **MUST NOT** override `doEffect`. Instead, you **MUST** override methods
    * `equip(player:Player,output:Boolean)` that should check whether item could be equipped by player by calling
        `canUse`, unequip item already equipped in that slot, put itself into the slot, and call `equipped(player,output)`
        to call possible equip effect
    * `unequip(player:Player,output:Boolean)` that should remove itself from player's slot and call `unequipped(player,output)`
        to call possible unequip effect.

    Also you **CAN** override methods `equipEffect(player,output)` and `unequipEffect(player,output)` to display
    some messages or add/remove PerkLib. Overrideable method `unequipReturnItem` returns item that should be placed into
    inventory on unequip, or `null` if item simply disappears. Example cases when you need to override this method are:

    * `ComfortableUnderclothes`, `Fists`, and `GooArmor` that return `null`
    * `ComfortableClothes` that return `this` but if the clothes were transformed into others by fetish cultists/zealots
        (which is done by `player.modArmorName`), displays message of them turning into comfortable clothes.
    * Urta's `LeatherArmorSegments` turns into default leather armor on unequip.

    You cannot instantiate `Equipable`, instead, you should use one of the subclasses:

    1. `Armor`. Armor has 3 more properties: `name` (displayable name, shorter than `longName`), `def`, and `perk`.
        `perk` defines armor class: `"Light"`/`"Medium"`/`"Heavy"` but could be empty string.
        Armor is equipped in `player.armor` slot, and when unequipped, is replaced by _"comfortable underclothes"_.
        You can create instances of this class, specify everything you need in the constructor. That armor will have
        no `equipEffect`/`unequipEffect` and could be equipped by anyone.

        * `ArmorWithPerk` is a subclass of `Armor` that adds a player perk on equip and removes in on unequip. Perk
            name and properties are set up in the constructor.

        To fine-tune armor with custom `equipEffect`/`unequipEffect`/`canUse`, or situation-dependent properties,
        subclass it.

    2. `Weapon`. Weapon has 3 more properties: `name` (displayable name, shorter than `longName`), `verb` (like _"hit"_,
        _"slash"_ to use in constructs like `"You "+weapon.verb+" "+monster.name+" with your "+weapon.name`, `attack`,
        and `perk`. `perk` defines weapon class: `"Light"`/`"Heavy"` but could be empty string.
        Weapon is equipped in `player.weapon` slot, and when unequipped, is replaced by _"fists"_.
        You can create instances of this class, specify everything you need in the constructor. That weapon will have
        no `equipEffect`/`unequipEffect` and could be equipped by anyone.

        To fine-tune weapon with custom `equipEffect`/`unequipEffect`/`canUse`, or situation-dependent propertiesm
        subclass it.

Note: `WingStick` though being a weapon, technically is a `Consumable`. Remember that when you check if item is a weapon;
 simple `itype is Weapon` might not be enough. **TODO** `ConsumableWeapon` for javelins, throwing daggers, grenades,
 spell scrolls?

## Item libraries

As mentioned before, only **one** instance of each `ItemType` should be created. Current game architecture suggests them
being `public const` fields of item library classes, and each item library is a `public` field of `CoC` game class.

For examples, see `ConsumableLib` and `CoC.consumables`, `WeaponLib` and `CoC.weapons` etc.

Item libraries usually subclass `BaseContent` to get access to handy methods and create their own handy methods to
 quickly create `ItemType`s for the library. See below.

## Adding new item

### Adding new armor

`ArmorLib` has methods
 `mk(id,shortName,name,longName,def,value,description,perk="")` to create `Armor` and
 `mk2(id,shortName,name,longName,def,value,description,perk,playerPerkName,playerPerkV1,playerPerkV2,playerPerkV3,playerPerkV4,playerPerkDesc)` to create `ArmorWithPerk`.

See examples.

TODO moar on custom armorz

### Adding new weapon

`WeaponLib` has method
 `mk(id,shortName,name,longName,verb,attack,value,description,perk="")` to create `Weapon`.

See examples.

TODO moar on custom weaponz

### Adding new consumable

`ConsumableLib` has method
 `mk(id,shortName,longName,effect,description,value=DEFAULT_VALUE)` to create `SimpleConsumable`.
`effect` should be `function(player:Player):void`.
Legacy consumable effects are stored in `Mutations` class, which is accessible via `m` property.
If you want to have one function to handle different consumables
 (like, `succubiMilk` for both tainted and pure versions),
 declare it with parameters and **`player` argument last**;
 then use `curry` function (see bottom of this readme) to create partial function call
  (e.g. `curry(m.succubiMilk,true)` will return `function(player:Player){m.succubiMilk(true,player)}`.

See examples.

TODO moar on custom consumablez

### Adding new other item

`UseableLib` holds items that are useable but not consumed when used (reagents, kitsune statue).
It has method `mk(id,shortName,longName,effect,description,value=DEFAULT_VALUE)` to create `SimpleUseable`.
`effect` should be `function(player:Player):void`.

See examples.

`MiscItemLib` is currently empty and probably should contain all other kinds of items.

# Scene classes

## Class hierarchy

These are not strict rules but a general directions.

All scenes should be put it BaseContent subclasses. How many classes per event it developer to decide.

An instance of this scene class should be available from `CoC` (declared as field and instantiated in the declaration),
but not necessarily directly. It is preferable that location-specific scenes should be fields of corresponding location
scenes. In code referencing a "foreign" scene to call an event could be something like
`doNext(kGAMECLASS.telAdre.bakeryScene.bakeryuuuuuu);` . For such location-specific scenes it is good to subclass them
from common superclass containing handy methods to access instance of their parent and other helpy stuff (see
_Scenes/Places/TelAdre/TelAdreAbstractContent.as_ )

Due to legacy reasons, if a NPC is combatable, its Monster subclass should be named after him (`Npcname`), and its BaseContent
subclass should be named `Npcname+"Scene"`. However, if a non-combatable NPC (with BaseContent subclass named `npcname`)
becomes combatable in future releases, either its Monster subclass should be named `Npcname+"Combat"`, or the original
`Npcname` should be renamed to `NpcnameScene` and its Monster subclass should be named `Npcname`. Messy.

## Class members

1. Remember that all variables declared in the Scene will not be saved/loaded in any way, or even resetted after save/load
   unless there is specific code for that in global save/load/newgame method.
2. Please keep methods as invisible as possible; a good start would be declare every function private and make them
   public/internal when needed.
3. For debugging purposes methods of all classes in package _classes/Scenes/_ or its subpackages are listed in
   name-by-ref dictionary `funcLookups`, see _engineCore.as_ (Before that only CoC methods were saved in that dictionary).
   If for whatever reason your scene is in another package, add an `[Scene]` metadata to it (see declaration of
   `testContent` in `CoC` for example.

# File placement

## Locations

A **Location** is either **Camp**, **Area**, **Place**, **Dungeon**, or **Quest**.

1. An **Area** is package, which main scene is directly available from **Explore** menu.
2. A **Place** is package, which main scene is available from **Explore** -> **Places** menu, but is not a **Dungeon**.
3. A definitions of **Dungeon** and **Quest** assumed obvious.
4. A BaseContent subclass for general **Area** or **Place** should be placed in either _Scenes/Areas_ or _Scenes/Places_,
   correspondingly.

### Notes

1. **Locations** that share many common scenes could be joined in one package, like **Forest** and **Deepwoods**.
2. Events for **Explore** -> **Explore** should be placed into _Scenes/Explore_.

## NPCs

1. If a **NPC** cannot be discovered directly by visiting **Location**, put it in _Scenes/NPCs_.
2. If a **NPC** can be made a follower/slave/lover/etc, or contains highly detailed dialogue/scene,
   put it in _Scenes/NPCs_.
1. If a **NPC** can be met in a specific **Place** or **Dungeon**, put it in its corresponding package.
3. Else put it in corresponding **Area** package.

## Monsters

1. **Monster** classes that are related to **NPCs** should be placed in same package as corresponding **NPCs**.
2. **Monsters** that mostly could be found in one **Location** should be placed in that **Location** package.
3. Else put it in _Scenes/Monsters_.

## Other scenes

If it does not fit **Camp** scenes, put it whatever it seems logial and where similar scenes may appear.

# Utility functions

During all these refucktorings, I've found `createCallBackFunction` not enough (also, I've moved it to new `Utils` class)
So I've added more functions, (`curry` is enough for most cases):

* `curry(func,...args)` is a partial function call. It returns a function, that will call `func` with first
    arguments already applied: `curry(func,arg1,...,argN)(arg2_1,...,arg2_M) = func(arg1,...,argN,arg2_1,...arg2_M)`.
    For example, `SimpleUseable` accepts `function(player:Player)`, but some of the mutations are parametrized, e.g.
    Incubi Draft could be purified. So we make `function incubiDraft(purified:Boolean,player:Player)`, and to make
    a function reference to impure draft, we use `f=curry(incubiDraft,false)`, and `f(player)` will call
    `incubiDraft(false,player)`.
* `curry(func,arg)` is equivalent of `createCallBackFunction(func,arg)`.
* `lazyIndex(obj,...args)` is a lazy property access. It returns a function, that will dig into `obj`'s `args`
    and return whatever is last: `lazyIndex(obj,arg1,...,argN)()=obj["arg1"]..["argN"]`.
    For example, in cases when `game.telAdre` is not yet initialized (but `game` is), and
    you need to access function reference `game.telAdre.doSomething`, you can use `lazyIndex(game,"telAdre","doSomething")`.
* `lazyCallIndex(func,...args)` is a lazy property access of an unavailable object. It returns a function, that will call
    `func` and dig into result's properties specified by `args`:
    `lazyCallIndex(func,arg1,...,argN)() = func()["arg1"]..["argN"]`.
    Let us enhance previous example and suppose that we need to access same function reference `game.telAdre.doSomething`,
    but even `game` is not initialized. So we make `function getGame(){return game}` and use `lazyCallIndex`:
    `lazyCallindex(getGame,"telAdre","doSomething")`.
* `lazyCallIndexCall(func,...args1)` is the ultimate case when the returned function accepts arguments:
    `lazyCallIndexCall(func,args1_1,...,args1_N)(args2_1,...args2_M) = func()["args1_1"]...["args1_N"](args2_1,...,args2_M)`.
    Example how to use this monstrosity. Previous example, suppose `game.telAdre.doSomething` accepts argument.
    So we can do `f=lazyCallIndexCall(getGame,telAdre,doSomething)` and then `f(bar)` will call `getGame().telAdre.doSomething(bar)`.
* That above example is not type-safe or any kind of safe, so I prefer to use `f=function(bar:Bar){game.telAdre.doSomething(bar)}`


code:
package classes.Scenes.Seasonal {
	import classes.*;
	import classes.GlobalFlags.*;

	public class Seasons extends BaseContent {
		public function Seasons() {}

		public static const WINTER:int = 0;
		public static const SPRING:int = 1;
		public static const SUMMER:int = 2;
		public static const AUTUMN:int = 3;
		public static const WITCH:int = -1;

		//For consistency, all holidays last 15 days, centred on the day itself (or the average, for holidays without a fixed date)
		//Except April Fools, that's special and one-day-only.

		public function isItSaturnalia(strict:Boolean = false):Boolean {
			//December 25
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| (player.hasPerk(PerkLib.AChristmasCarol) && !strict)
				|| (date.month == 11 && date.date >= 18)
				|| (date.month == 0 && date.date <= 1);
		}

		public function isItAprilFools():Boolean {
			//April 1
			return (date.month == 3 && date.date == 1);
		}

		public function isItValentine(strict:Boolean = false):Boolean {
			//February 14
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| (date.month == 1 && date.date >= 7 && date.date <= 21);
		}

		public function isItHalloween(strict:Boolean = false):Boolean {
			//October 31
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| (date.month == 9 && date.date >= 24)
				|| (date.month == 10 && date.date <= 7)
				|| (flags[kFLAGS.PUMPKIN_SEEDS_EATEN] >= 4 && !strict);
		}

		public function isItEaster():Boolean {
			//April 8 (average)
			return flags[kFLAGS.ITS_EVERY_DAY] > 0
				|| (date.month == 3 && date.date <= 15);
		}

		public function isItThanksgiving():Boolean {
			//Novemeber 25 (average)
			return flags[kFLAGS.ITS_EVERY_DAY] > 0
				|| (date.month == 10 && date.date >= 18)
				|| (date.month == 11 && date.date <= 2)
				|| inventory.countTotalFoodItems() >= 15;
		}

		public function get season():int {
			//Northern hemisphere only, sorry to everyone living upside down
			switch (date.month) {
				case 11: case 0: case 1: return WINTER;
				case 2: case 3: case 4: return SPRING;
				case 5: case 6: case 7: return SUMMER;
				case 8: case 9: case 10: return AUTUMN;
				default: //It's apparently not a month. It's strange, so strange.
					return WITCH;
			}
		}

		public function isItWinter(strict:Boolean = false):Boolean {
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| season == WINTER;
		}

		public function isItSpring(strict:Boolean = false):Boolean {
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| season == SPRING;
		}

		public function isItSummer(strict:Boolean = false):Boolean {
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| season == SUMMER;
		}

		public function isItAutumn(strict:Boolean = false):Boolean {
			return (flags[kFLAGS.ITS_EVERY_DAY] > 0 && !strict)
				|| season == AUTUMN;
		}
	}
}


code:
package classes.Scenes.Seasonal
{
	import classes.*;
	import classes.GlobalFlags.*;

	public class XmasBase extends BaseContent
	{
		public var xmasElf:XmasElf = new XmasElf();
		public var xmasMisc:XmasMisc = new XmasMisc();
		public var jackFrost:XmasJackFrost = new XmasJackFrost();
		public var snowAngel:XmasSnowAngel = new XmasSnowAngel();

		public function XmasBase() {}
	}
}