code:
package classes
{
	import classes.BodyParts.*;
	import classes.lists.BodyPartLists;

	/**
	 * Character class for player and NPCs. Has subclasses Player and NonPlayer.
	 * @author Yoffy
	 */
	public class Character extends Creature
	{
		//BEARDS! Not used anywhere right now but WHO WANTS A BEARD?
		//Kitteh6660: I want a beard! I'll code in obtainable beard. (DONE!)

		//Used for hip ratings
		public var thickness:Number = 0;

		//Body tone i.e. Lithe, stocky, etc
		public var tone:Number = 0;

		private var _pregnancyType:int = 0;
		public function get pregnancyType():int { return _pregnancyType; }

		private var _pregnancyIncubation:int = 0;
		public function get pregnancyIncubation():int { return _pregnancyIncubation; }

		private var _buttPregnancyType:int = 0;
		public function get buttPregnancyType():int { return _buttPregnancyType; }

		private var _buttPregnancyIncubation:int = 0;
		public function get buttPregnancyIncubation():int { return _buttPregnancyIncubation; }

		public var pregnancyAllowHerm:Boolean = false;

		//Key items
		public var keyItems:/*KeyItem*/Array;

		public function Character()
		{
			keyItems = [];
		}

		//Return bonus fertility

		//return total fertility

		public function faceDesc():String
		{
			var faceo:String = "";
			//0-10
			if (femininity < 10)
			{
				faceo = "a square chin";
				if (!hasBeard())
					faceo += " and chiseled jawline";
				else
					faceo += ", chiseled jawline, and " + beardDesc();
			}
			//10+ -20
			else if (femininity < 20)
			{
				faceo = "a rugged looking " + faceDescript() + " ";
				if (hasBeard())
					faceo += "and " + beardDesc();
				faceo += "that's surely handsome";
			}
			//21-28
			else if (femininity < 28)
				faceo = "a well-defined jawline and a fairly masculine profile";
			//28+-35
			else if (femininity < 35)
				faceo = "a somewhat masculine, angular jawline";
			//35-45
			else if (femininity < 45)
				faceo = "the barest hint of masculinity on its features";
			//45-55
			else if (femininity <= 55)
				faceo = "an androgynous set of features that would look normal on a male or female";
			//55+-65
			else if (femininity <= 65)
				faceo = "a tiny touch of femininity to it, with gentle curves";
			//65+-72
			else if (femininity <= 72)
				faceo = "a nice set of cheekbones and lips that have the barest hint of pout";
			//72+-80
			else if (femininity <= 80)
				faceo = "a beautiful, feminine shapeliness that's sure to draw the attention of males";
			//81-90
			else if (femininity <= 90)
				faceo = "a gorgeous profile with full lips, a button nose, and noticeable eyelashes";
			//91-100
			else
				faceo = "a jaw-droppingly feminine shape with full, pouting lips, an adorable nose, and long, beautiful eyelashes";
			return faceo;
		}

		//Modify femininity!
		public function modFem(goal:Number, strength:Number = 1):String
		{
			var output:String = "";
			var old:String = faceDesc();
			var oldN:Number = femininity;
			var Changed:Boolean = false;
			//If already perfect!
			if (goal == femininity)
				return "";
			//If turning MANLYMAN
			if (goal < femininity && goal <= 50)
			{
				femininity -= strength;
				//YOUVE GONE TOO FAR! TURN BACK!
				if (femininity < goal)
					femininity = goal;
				Changed = true;
			}
			//if turning GIRLGIRLY, like duh!
			if (goal > femininity && goal >= 50)
			{
				femininity += strength;
				//YOUVE GONE TOO FAR! TURN BACK!
				if (femininity > goal)
					femininity = goal;
				Changed = true;
			}
			//Fix if it went out of bounds!
			if (findPerk(PerkLib.Androgyny) < 0)
				fixFemininity();
			//Abort if nothing changed!
			if (!Changed)
				return "";
			//See if a change happened!
			if (old != faceDesc())
			{
				//Gain fem?
				if (goal > oldN)
					output = "\n\nYour facial features soften as your body becomes more feminine. (+" + strength + ")";
				if (goal < oldN)
					output = "\n\nYour facial features harden as your body becomes more masculine. (+" + strength + ")";
			}
			//Barely noticable change!
			else
			{
				if (goal > oldN)
					output = "\n\nThere's a tingling in your " + faceDescript() + " as it changes imperceptibly towards being more feminine. (+" + strength + ")";
				else if (goal < oldN)
					output = "\n\nThere's a tingling in your " + faceDescript() + " as it changes imperceptibly towards being more masculine. (+" + strength + ")";
			}
			return output;
		}

		public function modThickness(goal:Number, strength:Number = 1):String
		{
			if (goal == thickness)
				return "";
			//Lose weight fatty!
			if (goal < thickness && goal < 50)
			{
				thickness -= strength;
				//YOUVE GONE TOO FAR! TURN BACK!
				if (thickness < goal)
					thickness = goal;
			}
			//Sup tubby!
			if (goal > thickness && goal > 50)
			{
				thickness += strength;
				//YOUVE GONE TOO FAR! TURN BACK!
				if (thickness > goal)
					thickness = goal;
			}
			//trace("MOD THICKNESS FIRE");
			//DIsplay 'U GOT FAT'
			if (goal >= thickness && goal >= 50)
				return "\n\nYour center of balance changes a little bit as your body noticeably widens. (+" + strength + " body thickness)";
			//GET THIN BITCH
			else if (goal <= thickness && goal <= 50)
				return "\n\nEach movement feels a tiny bit easier than the last.  Did you just lose a little weight!? (+" + strength + " thin)";
			return "";
		}

		public function modTone(goal:Number, strength:Number = 1):String
		{
			if (goal == tone)
				return "";
			//Lose muscle visibility!
			if (goal < tone && goal < 50)
			{
				tone -= strength;
				//YOUVE GONE TOO FAR! TURN BACK!
				if (tone < goal)
				{
					tone = goal;
					return "\n\nYou've lost some tone, but can't lose any more this way. (-" + strength + " muscle tone)";
				}
			}
			//MOAR hulkness
			if (goal > tone && goal > 50)
			{
				tone += strength;
				//YOUVE GONE TOO FAR! TURN BACK!
				if (tone > goal)
				{
					tone = goal;
					return "\n\nYou've gained some muscle tone, but can't gain any more this way. (+" + strength + " muscle tone)";
				}
			}
			//DIsplay BITCH I WORK OUT
			if (goal >= tone && goal > 50)
				return "\n\nYour body feels a little more solid as you move, and your muscles look slightly more visible. (+" + strength + " muscle tone)";
			//Display DERP I HAVE GIRL MUSCLES
			else if (goal <= tone && goal < 50)
				return "\n\nMoving brings with it a little more jiggle than you're used to.  You don't seem to have gained weight, but your muscles look less visible. (-" + strength + " muscle tone)";
			return "";
		}

		//Run this every hour to 'fix' femininity.
		public function fixFemininity():String
		{
			var output:String = "";
			//Genderless/herms share the same bounds
			if (gender == 0 || gender == 3)
			{
				if (femininity < 20)
				{
					output += "\nYour incredibly masculine, chiseled features become a little bit softer from your body's changing hormones.";
					/*if (hasBeard())
					{
						output += "  As if that wasn't bad enough, your " + beard() + " falls out too!";
						beard.length = 0;
						beardStyle = 0;
					}*/
					output += "\n";
					femininity = 20;
				}
				else if (femininity > 85)
				{
					output += "\nYou find your overly feminine face loses a little bit of its former female beauty due to your body's changing hormones.\n";
					femininity = 85;
				}
			}
			//GURLS!
			else if (gender == 2)
			{
				if (femininity < 30)
				{
					output += "\nYour incredibly masculine, chiseled features become a little bit softer from your body's changing hormones.";
					/*if (hasBeard())
					{
						output += "  As if that wasn't bad enough, your " + beard() + " falls out too!";
						beard.length = 0;
						beardStyle = 0;
					}*/
					output += "\n";
					femininity = 30;
				}
			}
			//BOIZ!
			else if (gender == 1)
			{
				if (femininity > 71)
				{
					output += "\nYou find your overly feminine face loses a little bit of its former female beauty due to your body's changing hormones.\n";
					femininity = 71;
				}
				/*if (femininity > 40 && hasBeard())
				{
					output += "\nYour beard falls out, leaving you with " + faceDesc() + ".\n";
					beard.length = 0;
					beardStyle = 0;
				}*/
			}
			/*if (gender != 1 && hasBeard())
			{
				output += "\nYour beard falls out, leaving you with " + faceDesc() + ".\n";
				beard.length = 0;
				beardStyle = 0;
			}*/
			return output;
		}

		public function hasBeard():Boolean
		{
			return beard.length > 0;
		}

		public function beardDesc():String
		{
			if (hasBeard())
				return "beard";
			else
			{
				//CoC_Settings.error("");
				return "ERROR: NO BEARD! YOU ARE NOT A VIKING AND SHOULD TELL KITTEH IMMEDIATELY.";
			}
		}

		public function hasMuzzle():Boolean
		{
			return BodyPartLists.MUZZLES.indexOf(face.type) !== -1;
		}

		public function faceDescript():String
		{
			var stringo:String = "";
			if (face.type == Face.HUMAN)
				return "face";
			if (hasMuzzle())
			{
				if (int(Math.random() * 3) == 0 && face.type == Face.HORSE)
					stringo = "long ";
				if (int(Math.random() * 3) == 0 && face.type == Face.CAT)
					stringo = "feline ";
				if (int(Math.random() * 3) == 0 && face.type == Face.RHINO)
					stringo = "rhino ";
				if (int(Math.random() * 3) == 0 && (face.type == Face.LIZARD || face.type == Face.DRAGON))
					stringo = "reptilian ";
				if (int(Math.random() * 3) == 0 && face.type == Face.WOLF)
					stringo = "canine ";
				switch(rand(3)) {
					case 0:
						return stringo + "muzzle";
					case 1:
						return stringo + "snout";
					case 2:
						return stringo + "face";
					default:
						return stringo + "face";
				}
			}
			//3 - cowface
			if (face.type == Face.COW_MINOTAUR)
			{
				if (Math.floor(Math.random() * 4) == 0)
					stringo = "bovine ";
				if (int(Math.random() * 2) == 0)
					return "muzzle";
				return stringo + "face";
			}
			//4 - sharkface-teeth
			if (face.type == Face.SHARK_TEETH)
			{
				if (Math.floor(Math.random() * 4) == 0)
					stringo = "angular ";
				return stringo + "face";
			}
			if (face.type == Face.PIG || face.type == Face.BOAR)
			{
				if (Math.floor(Math.random() * 4) == 0)
					stringo = (face.type == Face.PIG ? "pig" : "boar") + "-like ";
				if (Math.floor(Math.random() * 4) == 0)
					return stringo + "snout";
				return stringo + "face";
			}
			return "face";
		}

		public function hasLongTail():Boolean
		{
			if (isNaga()) return true;

			return BodyPartLists.LONG_TAILS.indexOf(tail.type) !== -1;
		}

		public function isPregnant():Boolean { return _pregnancyType != 0; }

		public function isButtPregnant():Boolean { return _buttPregnancyType != 0; }

		/**
		 * Impregnate the character with the given pregnancy type if the total fertility
		 * is greater or equal to the roll.
		 * @param	type the type of pregnancy (@see PregnancyStore.PREGNANCY_xxx)
		 * @param	incubationDuration the incubation duration
		 * @param	maxRoll the possible maximum roll for an impregnation check
		 * @param	forcePregnancy specify a large bonus or malus to fertility (0 = no bonus, positive number = guaranteed pregnancy, negative number = no pregnancy)
		 */
		public function knockUp(type:int = 0, incubationDuration:int = 0, maxRoll:int = 100, forcePregnancy:int = 0, forceAllowHerm:Boolean = false):void
		{
			//Contraceptives cancel!
			if (hasStatusEffect(StatusEffects.Contraceptives) && forcePregnancy < 1)
				return;

			var bonus:int = 0;

			// apply fertility bonus or malus
			if (forcePregnancy >= 1)
				bonus = 9000;
			if (forcePregnancy <= -1)
				bonus = -9000;

			//If not pregnant and fertility wins out:
			if (pregnancyIncubation == 0 && totalFertility() + bonus > Math.floor(Math.random() * maxRoll) && hasVagina())
			{
				knockUpForce(type, incubationDuration, forceAllowHerm);
				//trace("PC Knocked up with pregnancy type: " + type + " for " + incubationDuration + " incubation.");
			}

			//Chance for eggs fertilization - ovi elixir and imps excluded!
			if (type != PregnancyStore.PREGNANCY_IMP && type != PregnancyStore.PREGNANCY_OVIELIXIR_EGGS && type != PregnancyStore.PREGNANCY_ANEMONE)
			{
				if (findPerk(PerkLib.SpiderOvipositor) >= 0 || findPerk(PerkLib.BeeOvipositor) >= 0)
				{
					if (totalFertility() + bonus > Math.floor(Math.random() * maxRoll))
					{
						fertilizeEggs();
					}
				}
			}

		}

		 /**
		  * Forcefully override the characters pregnancy. If no pregnancy type is provided,
		  * any current pregancy is cleared.
		  *
		  * Note: A more complex pregnancy function used by the character is Character.knockUp
		  * The character doesn't need to be told of the last event triggered, so the code here is quite a bit simpler than that in PregnancyStore.
		  * @param	type the type of pregnancy (@see PregnancyStore.PREGNANCY_xxx)
		  * @param	incubationDuration the incubation duration
		  */
		public function knockUpForce(type:int = 0, incubationDuration:int = 0, forceAllowHerm:Boolean = false):void
		{
			//TODO push this down into player?
			_pregnancyType = type;
			_pregnancyIncubation = (type == 0 ? 0 : incubationDuration); //Won't allow incubation time without pregnancy type
			pregnancyAllowHerm = isHerm() || forceAllowHerm;
		}

		//fertility must be >= random(0-beat)
		public function buttKnockUp(type:int = 0, incubation:int = 0, beat:int = 100, arg:int = 0):void
		{
			//Contraceptives cancel!
			if (hasStatusEffect(StatusEffects.Contraceptives) && arg < 1)
				return;
			var bonus:int = 0;
			//If arg = 1 (always pregnant), bonus = 9000
			if (arg >= 1)
				bonus = 9000;
			if (arg <= -1)
				bonus = -9000;
			//If unpregnant and fertility wins out:
			if (buttPregnancyIncubation == 0 && totalFertility() + bonus > Math.floor(Math.random() * beat))
			{
				buttKnockUpForce(type, incubation);
				//trace("PC Butt Knocked up with pregnancy type: " + type + " for " + incubation + " incubation.");
			}
		}

		//The more complex buttKnockUp function used by the player is defined in Character.as
		public function buttKnockUpForce(type:int = 0, incubation:int = 0):void
		{
			_buttPregnancyType = type;
			_buttPregnancyIncubation = (type == 0 ? 0 : incubation); //Won't allow incubation time without pregnancy type
		}

		public function pregnancyAdvance():Boolean {
			if (_pregnancyIncubation > 0) _pregnancyIncubation--;
			if (_pregnancyIncubation < 0) _pregnancyIncubation = 0;
			if (_buttPregnancyIncubation > 0) _buttPregnancyIncubation--;
			if (_buttPregnancyIncubation < 0) _buttPregnancyIncubation = 0;
			return pregnancyUpdate();
		}

		public function pregnancyUpdate():Boolean { return false; }

		//Create a keyItem
		public function createKeyItem(keyName:String, value1:Number, value2:Number, value3:Number, value4:Number):void
		{
			var newKeyItem:KeyItem = new KeyItem();
			//used to denote that the array has already had its new spot pushed on.
			var arrayed:Boolean = false;
			//used to store where the array goes
			var keySlot:Number = 0;
			var counter:Number = 0;
			//Start the array if its the first bit
			if (keyItems.length == 0)
			{
				//trace("New Key Item Started Array! " + keyName);
				keyItems.push(newKeyItem);
				arrayed = true;
				keySlot = 0;
			}
			//If it belongs at the end, push it on
			if (keyItems[keyItems.length - 1].keyName < keyName && !arrayed)
			{
				//trace("New Key Item Belongs at the end!! " + keyName);
				keyItems.push(newKeyItem);
				arrayed = true;
				keySlot = keyItems.length - 1;
			}
			//If it belongs in the beginning, splice it in
			if (keyItems[0].keyName > keyName && !arrayed)
			{
				//trace("New Key Item Belongs at the beginning! " + keyName);
				keyItems.splice(0, 0, newKeyItem);
				arrayed = true;
				keySlot = 0;
			}
			//Find the spot it needs to go in and splice it in.
			if (!arrayed)
			{
				//trace("New Key Item using alphabetizer! " + keyName);
				counter = keyItems.length;
				while (counter > 0 && !arrayed)
				{
					counter--;
					//If the current slot is later than new key
					if (keyItems[counter].keyName > keyName)
					{
						//If the earlier slot is earlier than new key && a real spot
						if (counter - 1 >= 0)
						{
							//If the earlier slot is earlier slot in!
							if (keyItems[counter - 1].keyName <= keyName)
							{
								arrayed = true;
								keyItems.splice(counter, 0, newKeyItem);
								keySlot = counter;
							}
						}
						//If the item after 0 slot is later put here!
						else
						{
							//If the next slot is later we are go
							if (keyItems[counter].keyName <= keyName)
							{
								arrayed = true;
								keyItems.splice(counter, 0, newKeyItem);
								keySlot = counter;
							}
						}
					}
				}
			}
			//Fallback
			if (!arrayed)
			{
				//trace("New Key Item Belongs at the end!! " + keyName);
				keyItems.push(newKeyItem);
				keySlot = keyItems.length - 1;
			}

			keyItems[keySlot].keyName = keyName;
			keyItems[keySlot].value1 = value1;
			keyItems[keySlot].value2 = value2;
			keyItems[keySlot].value3 = value3;
			keyItems[keySlot].value4 = value4;
			//trace("NEW KEYITEM FOR PLAYER in slot " + keySlot + ": " + keyItems[keySlot].keyName);
		}

		//Remove a key item
		public function removeKeyItem(itemName:String):void
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
			{
				//trace("ERROR: KeyItem could not be removed because player has no key items.");
				return;
			}
			while (counter > 0)
			{
				counter--;
				if (keyItems[counter].keyName == itemName)
				{
					keyItems.splice(counter, 1);
					//trace("Attempted to remove \"" + itemName + "\" keyItem.");
					counter = 0;
				}
			}
		}

		public function addKeyValue(statusName:String, statusValueNum:Number = 1, newNum:Number = 0):void
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
			{
				return;
					//trace("ERROR: Looking for keyitem '" + statusName + "' to change value " + statusValueNum + ", and player has no key items.");
			}
			while (counter > 0)
			{
				counter--;
				//Find it, change it, quit out
				if (keyItems[counter].keyName == statusName)
				{
					if (statusValueNum < 1 || statusValueNum > 4)
					{
						//trace("ERROR: AddKeyValue called with invalid key value number.");
						return;
					}
					if (statusValueNum == 1)
						keyItems[counter].value1 += newNum;
					if (statusValueNum == 2)
						keyItems[counter].value2 += newNum;
					if (statusValueNum == 3)
						keyItems[counter].value3 += newNum;
					if (statusValueNum == 4)
						keyItems[counter].value4 += newNum;
					return;
				}
			}
			//trace("ERROR: Looking for keyitem '" + statusName + "' to change value " + statusValueNum + ", and player does not have the key item.");
		}

		public function keyItemv1(statusName:String):Number
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
			{
				return 0;
					//trace("ERROR: Looking for keyItem '" + statusName + "', and player has no key items.");
			}
			while (counter > 0)
			{
				counter--;
				if (keyItems[counter].keyName == statusName)
					return keyItems[counter].value1;
			}
			//trace("ERROR: Looking for key item '" + statusName + "', but player does not have it.");
			return 0;
		}

		public function keyItemv2(statusName:String):Number
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
			{
				return 0;
					//trace("ERROR: Looking for keyItem '" + statusName + "', and player has no key items.");
			}
			while (counter > 0)
			{
				counter--;
				if (keyItems[counter].keyName == statusName)
					return keyItems[counter].value2;
			}
			//trace("ERROR: Looking for key item '" + statusName + "', but player does not have it.");
			return 0;
		}

		public function keyItemv3(statusName:String):Number
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
			{
				return 0;
					//trace("ERROR: Looking for keyItem '" + statusName + "', and player has no key items.");
			}
			while (counter > 0)
			{
				counter--;
				if (keyItems[counter].keyName == statusName)
					return keyItems[counter].value3;
			}
			//trace("ERROR: Looking for key item '" + statusName + "', but player does not have it.");
			return 0;
		}

		public function keyItemv4(statusName:String):Number
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
			{
				return 0;
					//trace("ERROR: Looking for keyItem '" + statusName + "', and player has no key items.");
			}
			while (counter > 0)
			{
				counter--;
				if (keyItems[counter].keyName == statusName)
					return keyItems[counter].value4;
			}
			//trace("ERROR: Looking for key item '" + statusName + "', but player does not have it.");
			return 0;
		}

		public function removeKeyItems():void
		{
			var counter:Number = keyItems.length;
			while (counter > 0)
			{
				counter--;
				keyItems.splice(counter, 1);
			}
		}

		public function findKeyItem(keyName:String):Number
		{
			var counter:Number = keyItems.length;
			//Various Errors preventing action
			if (keyItems.length <= 0)
				return -2;
			while (counter > 0)
			{
				counter--;
				if (keyItems[counter].keyName == keyName)
					return counter;
			}
			return -1;
		}

		public function hasKeyItem(keyName:String):Boolean {
			var testFunc:Function = function(item:Object, i:int, array:Array):Boolean {
				if (item.keyName == keyName) return true;
				return false;
			}
			return keyItems.some(testFunc);
		}

		//Grow

		//BreastCup

		/*OLD AND UNUSED
		   public function breastCupS(rowNum:Number):String {
		   if (breastRows[rowNum].breastRating < 1) return "tiny";
		   else if (breastRows[rowNum].breastRating < 2) return "A";
		   else if (breastRows[rowNum].breastRating < 3) return "B";
		   else if (breastRows[rowNum].breastRating < 4) return "C";
		   else if (breastRows[rowNum].breastRating < 5) return "D";
		   else if (breastRows[rowNum].breastRating < 6) return "DD";
		   else if (breastRows[rowNum].breastRating < 7) return "E";
		   else if (breastRows[rowNum].breastRating < 8) return "F";
		   else if (breastRows[rowNum].breastRating < 9) return "G";
		   else if (breastRows[rowNum].breastRating < 10) return "GG";
		   else if (breastRows[rowNum].breastRating < 11) return "H";
		   else if (breastRows[rowNum].breastRating < 12) return "HH";
		   else if (breastRows[rowNum].breastRating < 13) return "HHH";
		   return "massive custom-made";
		 }*/
		public function viridianChange():Boolean
		{
			var count:int = cockTotal();
			if (count == 0)
				return false;
			while (count > 0)
			{
				count--;
				if (cocks[count].sock == "amaranthine" && cocks[count].cockType != CockTypesEnum.DISPLACER)
					return true;
			}
			return false;
		}

		public function hasKnot(arg:int = 0):Boolean
		{
			if (arg > cockTotal() - 1 || arg < 0)
				return false;
			return cocks[arg].hasKnot();
		}

		public function maxHunger():Number
		{
			return 100;
		}

		public function growHair(amount:Number = .1):Boolean {
			//Grow hair!
			var tempHair:Number = hair.length;
			if (hair.type == Hair.BASILISK_SPINES) return false;
			hair.length += amount;
			if (hair.type == Hair.BASILISK_PLUME && hair.length > 8) hair.length = 8;
			if (hair.length > 0 && tempHair == 0) {
				game.outputText("\nYou are no longer bald.  You now have " + hairDescript() + " coating your head.\n");
				return true;
			}
			else if (
				(hair.length >= 1 && tempHair < 1) ||
				(hair.length >= 3 && tempHair < 3) ||
				(hair.length >= 6 && tempHair < 6) ||
				(hair.length >= 10 && tempHair < 10) ||
				(hair.length >= 16 && tempHair < 16) ||
				(hair.length >= 26 && tempHair < 26) ||
				(hair.length >= 40 && tempHair < 40) ||
				(hair.length >= 40 && hair.length >= tallness && tempHair < tallness)
			) {
				game.outputText("\nYour hair's growth has reached a new threshold, giving you " + hairDescript() + ".\n");
				return true;
			}
			return false;
		}

		public function growBeard(amount:Number = .1):Boolean {
			//Grow beard!
			var tempBeard:Number = beard.length;
			beard.length += amount;
			if (beard.length > 0 && tempBeard == 0) {
				game.outputText("\nYou feel a tingling in your cheeks and chin.  You now have " + beardDescript() + " coating your cheeks and chin.\n");
				return true;
			}
			else if (beard.length >= 0.2 && tempBeard < 0.2) {
				game.outputText("\nYour beard's growth has reached a new threshold, giving you " + beardDescript() + ".\n");
				return true;
			}
			else if (beard.length >= 0.5 && tempBeard < 0.5) {
				game.outputText("\nYour beard's growth has reached a new threshold, giving you " + beardDescript() + ".\n");
				return true;
			}
			else if (beard.length >= 1.5 && tempBeard < 1.5) {
				game.outputText("\nYour beard's growth has reached a new threshold, giving you " + beardDescript() + ".\n");
				return true;
			}
			else if (beard.length >= 3 && tempBeard < 3) {
				game.outputText("\nYour beard's growth has reached a new threshold, giving you " + beardDescript() + ".\n");
				return true;
			}
			else if (beard.length >= 6 && tempBeard < 6) {
				game.outputText("\nYour beard's growth has reached a new threshold, giving you " + beardDescript() + ".\n");
				return true;
			}

			return false;
		}

		public function hairOrFur():String
		{
			return Appearance.hairOrFur(this);
		}

		public function hairOrFurColor():String
		{
			return Appearance.hairOrFurColor(this);
		}

		public function hairDescript():String
		{
			return Appearance.hairDescription(this);
		}

		public function beardDescript():String
		{
			return Appearance.beardDescription(this);
		}

		public function hipDescript():String
		{
			return Appearance.hipDescription(this);
		}

		public function assDescript():String
		{
			return buttDescript();
		}

		public function buttDescript():String
		{
			return Appearance.buttDescription(this);
		}

		public function tongueDescript():String
		{
			return Appearance.tongueDescription(this);
		}

		public function hornDescript():String
		{
			if (horns.type == Horns.WOODEN && horns.value == 1) return "wooden antlers";
			return Appearance.DEFAULT_HORN_NAMES[horns.type] + " horns";
		}

		public function tailDescript():String
		{
			return Appearance.tailDescript(this);
		}

		public function oneTailDescript():String
		{
			return Appearance.oneTailDescript(this);
		}

		public function neckDescript():String
		{
			return Appearance.neckDescript(this);
		}

		public function rearBodyDescript():String
		{
			return Appearance.rearBodyDescript(this);
		}

		public function wingsDescript():String
		{
			return Appearance.wingsDescript(this);
		}

		public function eyesDescript():String
		{
			return Appearance.eyesDescript(this);
		}

		public function extraEyesDescript():String
		{
			return Appearance.extraEyesDescript(this);
		}

		public function extraEyesDescriptShort():String
		{
			return Appearance.extraEyesDescriptShort(this);
		}

		public function nagaLowerBodyColor2():String
		{
			return Appearance.nagaLowerBodyColor2(this);
		}

		public function redPandaTailColor2():String
		{
			return Appearance.redPandaTailColor2(this);
		}
	}

}


code:
/*
   CoC Main File - This is what loads when the game begins. If you want to start understanding the structure of CoC,
   this is the place to start.
   First, we import all the classes from many different files across the codebase. It would be wise not to alter the
   order of these imports until more is known about what needs to load and when.
 */

package classes
{
	// BREAKING ALL THE RULES.
	import classes.*;
	import classes.GlobalFlags.*;
	import classes.Items.*;
	import classes.Parser.*;
	import classes.Scenes.*;
	import classes.Scenes.Areas.*;
	import classes.Scenes.Areas.Desert.*;
	import classes.Scenes.Areas.Forest.*;
	import classes.Scenes.Areas.HighMountains.*;
	import classes.Scenes.Areas.Mountain.*;
	import classes.Scenes.Areas.Swamp.*;
	import classes.Scenes.Combat.*;
	import classes.Scenes.Dungeons.*;
	import classes.Scenes.Dungeons.DeepCave.*;
	import classes.Scenes.Dungeons.DesertCave.*;
	import classes.Scenes.Dungeons.Factory.*;
	import classes.Scenes.Dungeons.HelDungeon.*;
	import classes.Scenes.Dungeons.LethicesKeep.*;
	import classes.Scenes.Explore.*;
	import classes.Scenes.Monsters.*;
	import classes.Scenes.Monsters.pregnancies.*;
	import classes.Scenes.NPCs.*;
	import classes.Scenes.NPCs.Pets.*;
	import classes.Scenes.NPCs.pregnancies.*;
	import classes.Scenes.Places.*;
import classes.Scenes.Places.Bazaar.DemonFistFighterScene;
import classes.Scenes.Quests.*;
	import classes.Scenes.Seasonal.*;
	import classes.content.*;
	import classes.display.*;
	import classes.internals.*;
	import coc.view.*;
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	import flash.text.*;
	import mx.logging.*;
	import mx.logging.targets.*;
	import classes.lists.Gender;

// This file contains most of the persistent gamestate flags.

	/*
	   One very important thing to know about descriptions in this game is that many words are based on hidden integer values.
	   These integers are compared to tables or queried directly to get the words used for particular parts of descriptions. For instance,
	   Ass below has variables for wetness, looseness, fullness, and virginity. You'll often find little tables like this
	   scattered through the code:
	   butt looseness
	   0 - virgin
	   1 - normal
	   2 - loose
	   3 - very loose
	   4 - gaping
	   5 - monstrous
	   Tracking down a full list of description variables, how their integer values translate to descriptions, and how to call them
	   would be a very useful task for anyone who wants to extend content using variables.
	   Further complicating this is that the code will also sometimes have a randomized list of words for certain things just to keep
	   the text from being too boring.
	 */

	// This line not necessary, but added because I'm pedantic like that.

// All the files below with Scenes loads the main content for the game.

	// Class based content? In my CoC?! It's more likely than you think!

	// All the imports below are for Flash.

	/****
	   classes.CoC: The Document class of Corruption of the Champions.
	 ****/

	// This class instantiates the game. If you create a new place/location/scene you'll likely have to add it into here.
	// Add in descriptions for the include statements. Many of the description text code is inside of these.
	// Suggest moving or removing old comments referencing things that aren't needed anymore.

	[SWF(width = "1000", height = "800", backgroundColor = "0x000000", pageTitle = "Corruption of Champions")]

	public class CoC extends MovieClip implements GuiInput
	{
		{
			/*
			 * This is a static initializer block, used as an ugly hack to setup
			 * logging before any of the class variables are initialized.
			 * This is done because they could log messages during construction.
			 */

			CoC.setUpLogging();
		}

		// Include the functions. ALL THE FUNCTIONS
		include "../../includes/debug.as";
		include "../../includes/eventParser.as";
		include "../../includes/engineCore.as";

		//Any classes that need to be made aware when the game is saved or loaded can add themselves to this array using saveAwareAdd.
		//	Once in the array they will be notified by Saves.as whenever the game needs them to write or read their data to the flags array.
		private static var _saveAwareClassList:Vector.<SaveAwareInterface> = new Vector.<SaveAwareInterface>();

		//Called by the saveGameObject function in Saves
		public static function saveAllAwareClasses(game:CoC):void
		{
			for (var sac:int = 0; sac < _saveAwareClassList.length; sac++)
				_saveAwareClassList[sac].updateBeforeSave(game);
		}

		//Called by the loadGameObject function in Saves
		public static function loadAllAwareClasses(game:CoC):void
		{
			for (var sac:int = 0; sac < _saveAwareClassList.length; sac++)
				_saveAwareClassList[sac].updateAfterLoad(game);
		}

		public static function saveAwareClassAdd(newEntry:SaveAwareInterface):void
		{
			_saveAwareClassList.push(newEntry);
		}

		//Any classes that need to be aware of the passage of time can add themselves to this array using timeAwareAdd.
		//	Once in the array they will be notified as each hour passes, allowing them to update actions, lactation, pregnancy, etc.
		private static var _timeAwareClassList:Vector.<TimeAwareInterface> = new Vector.<TimeAwareInterface>(); //Accessed by goNext function in eventParser
		private static var timeAwareLargeLastEntry:int = -1; //Used by the eventParser in calling timeAwareLarge
		private var playerEvent:PlayerEvents;

		public static function timeAwareClassAdd(newEntry:TimeAwareInterface):void
		{
			_timeAwareClassList.push(newEntry);
		}

		public static function timeAwareClassRemove(entry:TimeAwareInterface):Number{
			for (var counter:int = 0; counter < _timeAwareClassList.length; counter++) {
				if ((_timeAwareClassList[counter] as TimeAwareInterface) == entry){
					_timeAwareClassList.splice(counter,1);
					return counter;
				}
			}
			return -1;
		}

		private static var doCamp:Function; //Set by campInitialize, should only be called by playerMenu

		private static function campInitialize(passDoCamp:Function):void
		{
			doCamp = passDoCamp;
		}

		// /
		private var _perkLib:PerkLib = new PerkLib(); // to init the static
		private var _statusEffects:StatusEffects = new StatusEffects(); // to init the static
		private var _masteryLib:MasteryLib = new MasteryLib(); // to init the static
		public var charCreation:CharCreation = new CharCreation();
		public var playerAppearance:PlayerAppearance = new PlayerAppearance();
		public var playerInfo:PlayerInfo = new PlayerInfo();
		public var saves:Saves = new Saves(gameStateDirectGet, gameStateDirectSet);
		public var perkTree:PerkTree = new PerkTree();
		public var monsterAbilities:MonsterAbilities = new MonsterAbilities();
		// Items/
		public var mutations:Mutations = Mutations.init();
		public var consumables:ConsumableLib = new ConsumableLib();
		public var useables:UseableLib;
		public var weapons:WeaponLib = new WeaponLib();
		public var armors:ArmorLib = new ArmorLib();
		public var undergarments:UndergarmentLib = new UndergarmentLib();
		public var jewelries:JewelryLib = new JewelryLib();
		public var shields:ShieldLib = new ShieldLib();
		public var miscItems:MiscItemLib = new MiscItemLib();
		// Scenes/
		public var achievementList:Achievements = new Achievements();
		public var camp:Camp = new Camp(campInitialize);
		public var dreams:Dreams = new Dreams();
		public var dungeons:DungeonCore;
		public var equipmentUpgrade:ItemUpgrade = new ItemUpgrade();
		public var followerInteractions:FollowerInteractions = new FollowerInteractions();
		public var inventory:Inventory = new Inventory(saves);
		public var masturbation:Masturbation = new Masturbation();
		public var pregnancyProgress:PregnancyProgression;
		public var bimboProgress:BimboProgression = new BimboProgression();

		// Scenes/Areas/
		public var commonEncounters:CommonEncounters = new CommonEncounters(); // Common dependencies go first

		public var bog:Bog;
		public var desert:Desert;
		public var forest:Forest;
		public var deepWoods:DeepWoods;
		public var glacialRift:GlacialRift = new GlacialRift();
		public var highMountains:HighMountains;
		public var lake:Lake;
		public var mountain:Mountain;
		public var plains:Plains;
		public var swamp:Swamp;
		public var volcanicCrag:VolcanicCrag;

		public var exploration:Exploration = new Exploration(); //Goes last in order to get it working.
		// Scenes/Combat/
		public var combat:Combat = new Combat();
		public var combatAttackData:CombatAttackData = new CombatAttackData();
		// Scenes/Dungeons
		public var brigidScene:BrigidScene = new BrigidScene();
		public var lethicesKeep:LethicesKeep = new LethicesKeep();
		public var liddelliumEventDungeon:LiddelliumEventDungeon = new LiddelliumEventDungeon();
		// Scenes/Explore/
		public var gargoyle:Gargoyle = new Gargoyle();
		public var lumi:Lumi = new Lumi();
		public var giacomoShop:Giacomo = new Giacomo();
		// Scenes/Monsters/
		public var goblinScene:GoblinScene = new GoblinScene();
		public var goblinAssassinScene:GoblinAssassinScene = new GoblinAssassinScene();
        public var goblinSharpshooterScene:GoblinSharpshooterScene = new GoblinSharpshooterScene();
		public var goblinWarriorScene:GoblinWarriorScene = new GoblinWarriorScene();
		public var goblinShamanScene:GoblinShamanScene = new GoblinShamanScene();
		public var goblinElderScene:PriscillaScene = new PriscillaScene();
		public var impScene:ImpScene;
		public var mimicScene:MimicScene = new MimicScene();
		public var succubusScene:SuccubusScene = new SuccubusScene();
		public var beautifulSwordScene:BeautifulSwordScene = new BeautifulSwordScene();
		// Scenes/NPC/
		public var amilyScene:AmilyScene;
		public var anemoneScene:AnemoneScene;
		public var arianScene:ArianScene = new ArianScene();
		public var ceraphScene:CeraphScene = new CeraphScene();
		public var coven:CorruptedCoven = new CorruptedCoven();
		public var ceraphFollowerScene:CeraphFollowerScene = new CeraphFollowerScene();
        public var demonfistScene:DemonFistFighterScene = new DemonFistFighterScene();
		public var emberScene:EmberScene;
		public var exgartuan:Exgartuan = new Exgartuan();
		public var helFollower:HelFollower = new HelFollower();
		public var helScene:HelScene = new HelScene();
		public var helSpawnScene:HelSpawnScene = new HelSpawnScene();
		public var holliScene:HolliScene = new HolliScene();
		public var isabellaScene:IsabellaScene = new IsabellaScene();
		public var isabellaFollowerScene:IsabellaFollowerScene = new IsabellaFollowerScene();
		public var izmaScene:IzmaScene;
		public var jojoScene:JojoScene;
		public var joyScene:JoyScene = new JoyScene();
		public var kihaFollower:KihaFollower = new KihaFollower();
		public var kihaScene:KihaScene = new KihaScene();
		public var latexGirl:LatexGirl = new LatexGirl();
		public var marbleScene:MarbleScene;
		public var marblePurification:MarblePurification = new MarblePurification();
		public var milkWaifu:MilkWaifu = new MilkWaifu();
		public var nephilaCovenScene:NephilaCovenScene = new NephilaCovenScene();
		public var nephilaCovenFollowerScene:NephilaCovenFollowerScene = new NephilaCovenFollowerScene();
		public var raphael:Raphael = new Raphael();
		public var rathazul:Rathazul = new Rathazul();
		public var sheilaScene:SheilaScene = new SheilaScene();
		public var shouldraFollower:ShouldraFollower = new ShouldraFollower();
		public var shouldraScene:ShouldraScene = new ShouldraScene();
		public var sophieBimbo:SophieBimbo = new SophieBimbo();
		public var sophieFollowerScene:SophieFollowerScene = new SophieFollowerScene();
		public var sophieScene:SophieScene = new SophieScene();
		public var sylviaScene:SylviaScene = new SylviaScene();
		public var urta:UrtaScene = new UrtaScene();
		public var urtaHeatRut:UrtaHeatRut = new UrtaHeatRut();
		public var urtaPregs:UrtaPregs;
		public var valeria:Valeria = new Valeria();
		public var vapula:Vapula = new Vapula();
		// Scenes/NPC/Pets
		public var akky:Akky = new Akky();
		// Scenes/Places/
		public var cabin:Cabin = new Cabin();
		public var bazaar:Bazaar = new Bazaar();
		public var boat:Boat = new Boat();
		public var farm:Farm = new Farm();
		public var owca:Owca = new Owca();
		public var telAdre:TelAdre;
		public var ingnam:Ingnam = new Ingnam();
		public var mothCave:MothCave = new MothCave;
		public var prison:Prison = new Prison();
		public var townRuins:TownRuins = new TownRuins();
		// Scenes/Seasonal/
		public var seasons:Seasons = new Seasons();
		public var aprilFools:AprilFools = new AprilFools();
		public var fera:Fera = new Fera();
		public var thanksgiving:Thanksgiving = new Thanksgiving();
		public var valentines:Valentines = new Valentines();
		public var xmas:XmasBase = new XmasBase();
		// Scenes/Quests/
		public var urtaQuest:UrtaQuest = new UrtaQuest();

		public var mainMenu:MainMenu = new MainMenu();
		public var gameSettings:GameSettings = new GameSettings();
		public var debugMenu:DebugMenu = new DebugMenu();
		public var crafting:Crafting = new Crafting();

		// Force updates in Pepper Flash ahuehue
		private var _updateHack:Sprite = new Sprite();

		public var mainViewManager:MainViewManager = new MainViewManager();
		//Scenes in includes folder GONE! Huzzah!

		public var bindings:Bindings = new Bindings();
		public var output:Output = Output.init();
		//public var credits:Credits = Credits.init();
		/****
		   This is used purely for bodges while we get things cleaned up.
		   Hopefully, anything you stick to this object can be removed eventually.
		   I only used it because for some reason the Flash compiler wasn't seeing
		   certain functions, even though they were in the same scope as the
		   function calling them.
		 ****/

		public var mainView:MainView;

		public var parser:Parser;

		// ALL THE VARIABLES:
		// Declare the various global variables as class variables.
		// Note that they're set up in the constructor, not here.
		public var debug:Boolean;
		public var ver:String;
		public var version:String;
		public var versionID:uint = 0;
		public var permObjVersionID:uint = 0;
		public var mobile:Boolean;
		public var images:ImageManager;
		public var player:Player;
		public var player2:Player;
		public var monster:Monster;
		public var monsterArray:Vector.<Monster> = new Vector.<Monster>();
		public var counters:RootCounters;
		public var fetishManager:FetishManager = new FetishManager();
		public var flags:DefaultDict;
		public var achievements:DefaultDict;
		private var _gameState:int;

		public function get gameState():int
		{
			return _gameState;
		}
		public var time:Time;

		public var temp:int;
		public var args:Array;
		public var funcs:Array;
		public var oldStats:*; // I *think* this is a generic object
		public var inputManager:InputManager;

		public var kFLAGS_REF:*;
		public var kACHIEVEMENTS_REF:*;

		public function clearOutput():void
		{
			output.clear(true);
		}

		public function rawOutputText(text:String):void
		{
			output.raw(text);
		}

		public function outputText(text:String):void
		{
			output.text(text);
		}

		public function displayHeader(string:String):void
		{
			output.text(output.formatHeader(string));
		}

		public function formatHeader(string:String):String
		{
			return output.formatHeader(string);
		}

		public function get inCombat():Boolean
		{
			return _gameState == 1;
		}

		public function set inCombat(value:Boolean):void
		{
			_gameState = (value ? 1 : 0);
		}

		public function gameStateDirectGet():int
		{
			return _gameState;
		}

		public function gameStateDirectSet(value:int):void
		{
			_gameState = value;
		}

		public function rand(max:int):int
		{
			return Utils.rand(max);
		}

		public function randBetween(min:Number, max:Number, inclusive:Boolean = true):int
		{
			return Utils.randBetween(min,max,inclusive);
		}

		//System time
		public var date:Date = new Date();

		//Mod save version.
		public var modSaveVersion:Number = 15;
		public var levelCap:Number = 120;

		//dungeoneering variables (If it ain't broke, don't fix it)
		public var inDungeon:Boolean = false;
		public var dungeonLoc:int = 0;

		// To save shitting up a lot of code...
		public var inRoomedDungeon:Boolean = false;
		public var inRoomedDungeonResume:Function = null;
		public var inRoomedDungeonName:String = "";

		public var timeQ:Number = 0;
		public var campQ:Boolean = false;

		private static var traceTarget:TraceTarget;

		private static function setUpLogging():void
		{
			traceTarget = new TraceTarget();

			traceTarget.level = LogEventLevel.WARN;

			CONFIG::debug
			{
				traceTarget.level = LogEventLevel.DEBUG;
			}

			//Add date, time, category, and log level to the output
			traceTarget.includeDate = true;
			traceTarget.includeTime = true;
			traceTarget.includeCategory = true;
			traceTarget.includeLevel = true;

			// let the logging begin!
			Log.addTarget(traceTarget);
		}

		/**
		 * Create scenes that use the new pregnancy system. This method is public to allow for simple testing.
		 * @param pregnancyProgress Pregnancy progression to use for scenes, which they use to register themself
		 */
		public function createScenes(pregnancyProgression:PregnancyProgression): void {
			dungeons = new DungeonCore(pregnancyProgression);

			bog = new Bog(pregnancyProgression, output);
			mountain = new Mountain(pregnancyProgression, output);
			highMountains = new HighMountains(pregnancyProgression, output);
			volcanicCrag = new VolcanicCrag(pregnancyProgression, output);
			swamp = new Swamp(pregnancyProgression, output);
			plains = new Plains(pregnancyProgression, output);
			forest = new Forest(pregnancyProgression, output);
			deepWoods = new DeepWoods(forest);
			desert = new Desert(pregnancyProgression, output);

			telAdre = new TelAdre(pregnancyProgression);

			impScene = new ImpScene(pregnancyProgression, output);
			anemoneScene = new AnemoneScene(pregnancyProgression, output);
			marbleScene = new MarbleScene(pregnancyProgression, output);
			jojoScene = new JojoScene(pregnancyProgression, output);
			amilyScene = new AmilyScene(pregnancyProgression, output);
			izmaScene = new IzmaScene(pregnancyProgression, output);
			lake = new Lake(pregnancyProgression, output);

			// not assigned to a variable as it is self-registering, PregnancyProgress will keep a reference to the instance
			new PlayerCentaurPregnancy(pregnancyProgression, output);
			new PlayerBunnyPregnancy(pregnancyProgression, output, mutations);
			new PlayerBenoitPregnancy(pregnancyProgression, output);
			new PlayerOviElixirPregnancy(pregnancyProgression, output);

			emberScene = new EmberScene(pregnancyProgression);
			urtaPregs = new UrtaPregs(pregnancyProgression);

		}

		/**
		 * Create the main game instance.
		 * If a stage is injected it will be use instead of the one from the superclass.
		 *
		 * @param injectedStage if not null, it will be used instead of this.stage
		 */
		public function CoC(injectedStage:Stage = null)
		{
			var stageToUse:Stage;

			if (injectedStage != null)
			{
				stageToUse = injectedStage;
			}
			else
			{
				stageToUse = this.stage;
			}

			// Cheatmode.
			kGAMECLASS = this;

			this.pregnancyProgress = new PregnancyProgression();
			createScenes(pregnancyProgress);

			useables = new UseableLib();

			this.kFLAGS_REF = kFLAGS;
			this.kACHIEVEMENTS_REF = kACHIEVEMENTS;
			// cheat for the parser to be able to find kFLAGS
			// If you're not the parser, DON'T USE THIS

			this.parser = new Parser(this, CoC_Settings);

			try
			{
				this.mainView = new MainView( /*this.model*/);
				if (CoC_Settings.charviewEnabled)
					this.mainView.charView.reload();
			}
			catch (e:Error)
			{
				throw Error(e.getStackTrace());
			}
			this.mainView.name = "mainView";
			this.mainView.addEventListener(Event.ADDED_TO_STAGE, Utils.curry(_postInit, stageToUse));
			stageToUse.addChild(this.mainView);
		}

		private function _postInit(stageToUse:DisplayObjectContainer, e:Event):void
		{
			// Hooking things to MainView.
			this.mainView.onNewGameClick = charCreation.newGameGo;
			this.mainView.onAppearanceClick = playerAppearance.appearance;
			this.mainView.onDataClick = saves.saveLoad;
			this.mainView.onLevelClick = playerInfo.levelUpGo;
			this.mainView.onPerksClick = playerInfo.displayPerks;
			this.mainView.onStatsClick = playerInfo.displayStats;
			this.mainView.onBottomButtonClick = function(i:int):void
			{
				output.record("<br>[" + output.button(i).labelText + "]<br>");
			};

			// Set up all the messy global stuff:

			// ******************************************************************************************

			var mainView:MainView = this.mainView;

			/**
			 * Global Variables used across the whole game. I hope to whittle it down slowly.
			 */

			/**
			 * System Variables
			 * Debug, Version, etc
			 */
			debug = false; //DEBUG, used all over the place
			version = "/hgg/ mod 1.4.5"; //Version NUMBER
			version += " (<b>The Edge of the Garden</b>)"; //Version TEXT

			//Indicates if building for mobile?
			mobile = false;

			this.images = new ImageManager(stageToUse.stage, mainView);
			this.inputManager = new InputManager(stageToUse.stage, mainView, false);
			include "../../includes/ControlBindings.as";

			//} endregion

			/**
			 * Player specific variables
			 * The player object and variables associated with the player
			 */
			//{ region PlayerVariables

			//The Player object, used everywhere
			player = new Player();
			player2 = new Player();
			playerEvent = new PlayerEvents();

			//Used in perk selection, mainly eventParser, input and engineCore
			//tempPerk = null;

			//Create monster, used all over the place
			monster = new Monster();
			//} endregion

			/**
			 * State Variables
			 * They hold all the information about item states, menu states, game states, etc
			 */
			//{ region StateVariables

			//User all over the place whenever items come up

			//The extreme flag state array. This needs to go. Holds information about everything, whether it be certain attacks for NPCs
			//or state information to do with the game.
			flags = new DefaultDict();
			achievements = new DefaultDict();

			/**
			 * Used everywhere to establish what the current game state is
			 * 0 = normal
			 * 1 = in combat
			 * 2 = in combat in grapple
			 * 3 = at start or game over screen
			 */
			_gameState = 0;

			/**
			 * Display Variables
			 * Variables that hold display information like number of days and all the current displayed text
			 */
			//{ region DisplayVariables

			//Holds the date and time display in the bottom left
			time = new Time();

			//The string holds all the "story" text, mainly used in engineCore
			//}endregion

			// These are toggled between by the [home] key.
			mainView.textBGTranslucent.visible = true;
			mainView.textBGWhite.visible = false;
			mainView.textBGTan.visible = false;

			// *************************************************************************************
			//Workaround.
			mainViewManager.registerShiftKeys();
			exploration.configureRooms();
			lethicesKeep.configureRooms();
			dungeons.map = new DungeonMap();

			temp = 0; //Fenoxo loves his temps

			//Used to set what each action buttons displays and does.
			args = [];
			funcs = [];

			//Used for stat tracking to keep up/down arrows correct.
			oldStats = {};
			oldStats.oldStr = 0;
			oldStats.oldTou = 0;
			oldStats.oldSpe = 0;
			oldStats.oldInte = 0;
			oldStats.oldSens = 0;
			oldStats.oldLib = 0;
			oldStats.oldCor = 0;
			oldStats.oldHP = 0;
			oldStats.oldLust = 0;
			oldStats.oldFatigue = 0;
			oldStats.oldHunger = 0;

			//model.maxHP = maxHP;

			// ******************************************************************************************

			/*mainView.aCb.items = [{label: "TEMP", perk: new Perk(PerkLib.Acclimation)}];
			mainView.aCb.addEventListener(Event.SELECT, playerInfo.changeHandler);*/

			//Register the classes we need to be able to serialize and reconstitute so
			// they'll get reconstituted into the correct class when deserialized
			registerClassAlias("AssClass", Ass);
			registerClassAlias("Character", Character);
			registerClassAlias("Cock", Cock);
			registerClassAlias("CockTypesEnum", CockTypesEnum);
			registerClassAlias("Enum", Enum);
			registerClassAlias("Creature", Creature);
			registerClassAlias("ItemSlotClass", ItemSlot);
			registerClassAlias("KeyItemClass", KeyItem);
			registerClassAlias("Monster", Monster);
			registerClassAlias("Player", Player);
			registerClassAlias("StatusEffectClass", StatusEffect);
			registerClassAlias("Vagina", Vagina);

			//Hide sprites
			mainView.hideSprite();
			//Hide images
			mainView.hideImage();
			//Hide up/down arrows
			mainView.statsView.hideUpDown();

			this.addFrameScript(0, this.run);
		}

		public function run():void
		{
			//Set up stage
			stage.focus = kGAMECLASS.mainView.mainText;
			mainView.eventTestInput.x = -10207.5;
			mainView.eventTestInput.y = -1055.1;
			mainViewManager.startUpButtons();
			saves.loadPermObject();
			mainViewManager.setTheme();
			mainView.setTextBackground(flags[kFLAGS.TEXT_BACKGROUND_STYLE]);
			//Now enter the main menu.
			mainMenu.mainMenu();

			this.stop();

			if (_updateHack)
			{
				_updateHack.name = "wtf";
				_updateHack.graphics.beginFill(0xFF0000, 1);
				_updateHack.graphics.drawRect(0, 0, 2, 2);
				_updateHack.graphics.endFill();

				stage.addChild(_updateHack);
				_updateHack.x = 999;
				_updateHack.y = 799;
			}
		}

		public function forceUpdate():void
		{
			_updateHack.x = 999;
			_updateHack.addEventListener(Event.ENTER_FRAME, moveHackUpdate);
		}

		public function moveHackUpdate(e:Event):void
		{
			_updateHack.x -= 84;

			if (_updateHack.x < 0)
			{
				_updateHack.x = 0;
				_updateHack.removeEventListener(Event.ENTER_FRAME, moveHackUpdate);
			}
		}

		public function spriteSelect(choice:Object = 0):void
		{
			// Inlined call from lib/src/coc/view/MainView.as
			// TODO: When flags goes away, if it goes away, replace this with the appropriate settings thing.
			if (choice <= 0 || choice == null || flags[kFLAGS.SHOW_SPRITES_FLAG] == 0)
			{
				mainViewManager.hideSprite();
			}
			else
			{
				if (choice is Class)
				{
                    mainView.minimapView.hide();
					mainViewManager.showSpriteBitmap(SpriteDb.bitmapData(choice as Class));
				}
				else
				{
					mainViewManager.hideSprite();
				}
			}
		}

		public function imageSelect(choice:Object = 0, x:int = 0, y:int = 0):void
		{
			// Inlined call from lib/src/coc/view/MainView.as
			// TODO: When flags goes away, if it goes away, replace this with the appropriate settings thing.
			if (choice <= 0 || choice == null || flags[kFLAGS.SHOW_SPRITES_FLAG] == 0)
			{
				mainViewManager.hideImage();
			}
			else
			{
				if (choice is Class)
				{
                    mainView.minimapView.hide();
					mainViewManager.showImageBitmap(ImageDb.bitmapData(choice as Class), x, y);
				}
				else
				{
					mainViewManager.hideImage();
				}
			}
		}

		// TODO remove once that GuiInput interface has been sorted
		public function addButton(pos:int, text:String = "", func1:Function = null, arg1:* = -9000, arg2:* = -9000, arg3:* = -9000, toolTipText:String = "", toolTipHeader:String = ""):CoCButton {
			return output.addButton(pos, text, func1, arg1, arg2, arg3, toolTipText, toolTipHeader);
		}

		public function setSexLeaveButton(func:Function = null, leaveText:String = "Leave",pos:int = 14,gender:int = -1,chanceBonus:int = 0):void {
			if(func == null) func = combat.cleanupAfterCombat;
			if(gender == -1) gender = monster.gender;
            if (player.playerResistSex(gender,chanceBonus)) addButton(pos, leaveText, func);
            else output.addButtonDisabled(pos, leaveText, "You can't resist the allure of sex!");
		}

		// TODO remove once that GuiInput interface has been sorted
		public function menu(): void {
			output.menu();
		}

		//Putting this here for easy access because Urta is fucking everywhere
		public function get urtaDisabled():Boolean {
			//Add checks for Urta flags later, so she won't be disabled if you've interacted much with her.
			return gameSettings.npcSettings.urtaDisabled && flags[kFLAGS.URTA_COMFORTABLE_WITH_OWN_BODY] <= 0 && flags[kFLAGS.TIMES_FUCKED_URTA] <= 0 && flags[kFLAGS.URTA_QUEST_STATUS] == 0;
		}

		public function addictionEnabled():Boolean {
			return !flags[kFLAGS.ADDICTIONS_DISABLED];
		}
	}
}

license: unknown


code:
package classes
{
	import classes.internals.LoggerFactory;
	import mx.logging.ILogger;
	/**
	 * ...
	 * @author Fake-Name
	 */
	public class CoC_Settings
	{
		private static const LOGGER:ILogger = LoggerFactory.getLogger(CoC_Settings);

		public static const debugBuild:Boolean = CONFIG::debug;
		public static const charviewEnabled:Boolean = true;

		// Horrible static abuse FTW
		public static const haltOnErrors:Boolean = false;
		private static const bufferSize:int = 50;

		/**
		 * trace("ERROR "+description);
		 * If haltOnErrors=true, throws Error
		 */
		public static function error(description:String=""):void {
			LOGGER.error("ERROR "+description);
			if (haltOnErrors) throw Error(description);
		}

		/**
		 * trace("ERROR Abstract method call: "+clazz+"."+method+"(). "+description);
		 * If haltOnErrors=true, throws Error
		 */
		public static function errorAMC(clazz:String,method:String,description:String=""):void{
			error("Abstract method call: "+clazz+"."+method+"(). "+description);
		}

		public function CoC_Settings()
		{

		}

	}

}


code:
package classes
{
	import classes.CockTypesEnum;
	import classes.internals.Serializable;
	import classes.internals.Utils;
	import classes.lists.GenitalLists;
	import mx.logging.ILogger;
	import classes.internals.LoggerFactory;

	public class Cock implements Serializable
	{
		private static const LOGGER:ILogger = LoggerFactory.getLogger(Cock);

		private static const SERIALIZATION_VERSION:int = 1;

		private static const OBJECT_NOT_FOUND:int = -1;

		public static const MAX_LENGTH:Number = 9999.9;
		public static const MAX_THICKNESS:Number = 999.9;
		public static const KNOTMULTIPLIER_NO_KNOT:Number = 1;

		private var _cockLength:Number;
		private var _cockThickness:Number;
		private var _cockType:CockTypesEnum;	//See CockTypesEnum.as for all cock types

		//Used to determine thickness of knot relative to normal thickness
		private var _knotMultiplier:Number;

		//Piercing info
		private var _isPierced:Boolean;
		private var _pierced:Number;
		private var _pShortDesc:String;
		private var _pLongDesc:String;

		//Sock
		private var _sock:String;

		/**
		 * @return string description of errors
		 */
		public function validate():String {
			var error:String = "";
			error += Utils.validateNonNegativeNumberFields(this,"Cock.validate",["cockLength","cockThickness","knotMultiplier","pierced"]);
			if (!_isPierced){
				if (_pShortDesc.length>0) error += "Not pierced but _pShortDesc = "+_pShortDesc+". ";
				if (_pLongDesc.length>0) error += "Not pierced but pLong = "+_pLongDesc+". ";
			} else {
				if (_pShortDesc.length==0) error += "Pierced but no _pShortDesc. ";
				if (_pLongDesc.length==0) error += "Pierced but no pLong. ";
			}
			return error;
		}

		//constructor. Default type is HUMAN
		public function Cock(i_cockLength:Number = 5.5, i_cockThickness:Number = 1, i_cockType:CockTypesEnum=null)
		{
			if (i_cockType === null) i_cockType = CockTypesEnum.HUMAN;
			_cockLength = i_cockLength;
			_cockThickness = i_cockThickness;
			_cockType = i_cockType;
			_pierced = 0;
			_knotMultiplier = KNOTMULTIPLIER_NO_KNOT;
			_isPierced = false;
			_pShortDesc = "";
			_pLongDesc = "";
			_sock = "";
		}

		//MEMBER FUNCTIONS
		public function cArea():Number
		{
			return cockThickness * cockLength;
		}

		public function growCock(lengthDelta:Number, bigCock:Boolean):Number
		{

			if (lengthDelta === 0) {
				LOGGER.error("growCock called with 0, aborting...")
				return lengthDelta;
			}

			var threshhold:int = 0;
			LOGGER.debug("growcock starting at: {0}", lengthDelta);

			if (lengthDelta > 0) { // growing
				LOGGER.debug("and growing...");
				threshhold = 24;
				// BigCock Perk increases incoming change by 50% and adds 12 to the length before diminishing returns set in
				if (bigCock) {
					LOGGER.debug("growCock found BigCock Perk");
					lengthDelta *= 1.5;
					threshhold += 12;
				}
				// Not a human cock? Multiple the length before dimishing returns set in by 3
				if (cockType !== CockTypesEnum.HUMAN)
					threshhold *= 2;
				// Modify growth for cock socks
				if (sock === "scarlet") {
					LOGGER.debug("growCock found Scarlet sock");
					lengthDelta *= 1.5;
				}
				else if (sock === "cobalt") {
					LOGGER.debug("growCock found Cobalt sock");
					lengthDelta *= .5;
				}
				// Do diminishing returns
				if (cockLength > threshhold)
					lengthDelta /= 4;
				else if (cockLength > threshhold / 2)
					lengthDelta /= 2;
			}
			else {
				LOGGER.debug("and shrinking...");

				threshhold = 0;
				// BigCock Perk doubles the incoming change value and adds 12 to the length before diminishing returns set in
				if (bigCock) {
					LOGGER.debug("growCock found BigCock Perk");
					lengthDelta *= 0.5;
					threshhold += 12;
				}
				// Not a human cock? Add 12 to the length before dimishing returns set in
				if (cockType !== CockTypesEnum.HUMAN)
					threshhold += 12;
				// Modify growth for cock socks
				if (sock === "scarlet") {
					LOGGER.debug("growCock found Scarlet sock");
					lengthDelta *= 0.5;
				}
				else if (sock === "cobalt") {
					LOGGER.debug("growCock found Cobalt sock");
					lengthDelta *= 1.5;
				}
				// Do diminishing returns
				if (cockLength < threshhold)
					lengthDelta /= 3;
				else if (cockLength < threshhold / 2)
					lengthDelta /= 2;
			}

			LOGGER.debug("then changing by: {0}", lengthDelta);

			cockLength += lengthDelta;

			if (cockLength < 1)
				cockLength = 1;

			if (cockThickness > cockLength * .33)
				cockThickness = cockLength * .33;

			return lengthDelta;
		}

		public function thickenCock(increase:Number, ignoreLimits:Boolean = false):Number
		{
			var amountGrown:Number = 0;
			var temp:Number = 0;
			if (increase > 0)
			{
				while (increase > 0)
				{
					if (increase < 1)
						temp = increase;
					else
						temp = 1;
					//Cut thickness growth for huge dicked
					if(!ignoreLimits){
                        if (cockThickness > 1 && cockLength < 12)
                        {
                            temp /= 4;
                        }
                        if (cockThickness > 1.5 && cockLength < 18)
                            temp /= 5;
                        if (cockThickness > 2 && cockLength < 24)
                            temp /= 5;
                        if (cockThickness > 3 && cockLength < 30)
                            temp /= 5;
                        //proportional thickness diminishing returns.
                        if (cockThickness > cockLength * .15)
                            temp /= 3;
                        if (cockThickness > cockLength * .20)
                            temp /= 3;
                        if (cockThickness > cockLength * .30)
                            temp /= 5;
                        //massive thickness limiters
                        if (cockThickness > 4)
                            temp /= 2;
                        if (cockThickness > 5)
                            temp /= 2;
                        if (cockThickness > 6)
                            temp /= 2;
                        if (cockThickness > 7)
                            temp /= 2;
					}
					//Start adding up bonus length
					amountGrown += temp;
					cockThickness += temp;
					temp = 0;
					increase--;
				}
				increase = 0;
			}
			else if (increase < 0)
			{
				while (increase < 0)
				{
					temp = -1;
                    if(!ignoreLimits){
                        //Cut length growth for huge dicked
                        if (cockThickness <= 1)
                            temp /= 2;
                        if (cockThickness < 2 && cockLength < 10)
                            temp /= 2;
                        //Cut again for massively dicked
                        if (cockThickness < 3 && cockLength < 18)
                            temp /= 2;
                        if (cockThickness < 4 && cockLength < 24)
                            temp /= 2;
                        //MINIMUM Thickness of OF .5!
                        if (cockThickness <= .5)
                            temp = 0;
                    }
					//Start adding up bonus length
					amountGrown += temp;
					cockThickness += temp;
					temp = 0;
					increase++;
				}
			}
			LOGGER.debug("thickenCock called and thickened by: {0}", amountGrown);
			return amountGrown;
		}

		/**
		 * Check if the given cockType supports a knot.
		 * @param cockType the cockType to check
		 * @return true if the cockType supports a knot
		 */
		public static function supportsKnot(cockType:CockTypesEnum):Boolean
		{
			return GenitalLists.KNOTTED_COCKS.indexOf(cockType) != OBJECT_NOT_FOUND;
		}

		public function get cockLength():Number
		{
			return _cockLength;
		}

		public function set cockLength(value:Number):void
		{
			_cockLength = value;
		}

		public function get cockThickness():Number
		{
			return _cockThickness;
		}

		public function set cockThickness(value:Number):void
		{
			_cockThickness = value;
		}

		public function get cockType():CockTypesEnum
		{
			return _cockType;
		}

		/**
		 * Sets the cock type.
		 * If the cock type does not support a knot, the knot is reset.
		 */
		public function set cockType(value:CockTypesEnum):void
		{
			_cockType = value;

			if (!supportsKnot(value) && this.knotMultiplier !== KNOTMULTIPLIER_NO_KNOT) {
				this.knotMultiplier = KNOTMULTIPLIER_NO_KNOT;
				LOGGER.debug("Cock type {0} does not support knots, setting knot knotMultiplier to {1}", value, knotMultiplier);
			}
		}

		public function hasKnot():Boolean
		{
			return knotMultiplier > KNOTMULTIPLIER_NO_KNOT;
		}

		public function get knotMultiplier():Number
		{
			return _knotMultiplier;
		}

		public function set knotMultiplier(value:Number):void
		{
			_knotMultiplier = value;
		}

		public function get isPierced():Boolean
		{
			return _isPierced;
		}

		public function set isPierced(value:Boolean):void
		{
			_isPierced = value;
		}

		public function get pShortDesc():String
		{
			return _pShortDesc;
		}

		public function set pShortDesc(value:String):void
		{
			_pShortDesc = value;
		}

		public function get pLongDesc():String
		{
			return _pLongDesc;
		}

		public function set pLongDesc(value:String):void
		{
			_pLongDesc = value;
		}

		public function get sock():String
		{
			return _sock;
		}

		public function set sock(value:String):void
		{
			_sock = value;
		}

		public function get pierced():Number
		{
			return _pierced;
		}

		public function set pierced(value:Number):void
		{
			_pierced = value;
		}

		public function serialize(relativeRootObject:*):void
		{
			relativeRootObject.cockThickness = this.cockThickness;
			relativeRootObject.cockLength = this.cockLength;
			relativeRootObject.cockType = this.cockType.Index;
			relativeRootObject.knotMultiplier = this.knotMultiplier;
			relativeRootObject.pierced = this.pierced;
			relativeRootObject.pShortDesc = this.pShortDesc;
			relativeRootObject.pLongDesc = this.pLongDesc;
			relativeRootObject.sock = this.sock;
		}

		public function deserialize(relativeRootObject:*):void
		{
			this.cockThickness = relativeRootObject.cockThickness;
			this.cockLength = relativeRootObject.cockLength;
			this.knotMultiplier = relativeRootObject.knotMultiplier;
			this.cockType = CockTypesEnum.ParseConstantByIndex(relativeRootObject.cockType);
			this.sock = relativeRootObject.sock;

			this.pierced = relativeRootObject.pierced;
			this.pShortDesc = relativeRootObject.pShortDesc;
			this.pLongDesc = relativeRootObject.pLongDesc;

			enforceCockSizeCaps();
		}

		private function enforceCockSizeCaps():void
		{
			if (this.cockLength > MAX_LENGTH) {
				this.cockLength = MAX_LENGTH;
			}

			if (this.cockThickness > MAX_THICKNESS) {
				this.cockThickness = MAX_THICKNESS;
			}
		}

		public function upgradeSerializationVersion(relativeRootObject:*, serializedDataVersion:int):void
		{
			switch(serializedDataVersion) {
				case 0:
					upgradeLegacyFormat(relativeRootObject);

				default:
					/*
					 * The default block is left empty intentionally,
					 * this switch case operates by using fall through behavior.
					 */
			}
		}

		/**
		 * Load un-versioned (legacy) cocks.
		 */
		private function upgradeLegacyFormat(relativeRootObject:*):void {
			LOGGER.info("Upgrading legacy save format...");

			if (relativeRootObject.sock === undefined) {
				relativeRootObject.sock = "";
				LOGGER.warn("Cock was missing sock field, setting to {0}", relativeRootObject.sock);
			}

			if (relativeRootObject.pShortDesc === "null" || relativeRootObject.pLongDesc === "null")
			{
				relativeRootObject.pShortDesc = "";
				relativeRootObject.pLongDesc = "";
				LOGGER.warn("Cock piercing description was null, setting to blank");
			}

			if (relativeRootObject.pierced === undefined)
			{
				relativeRootObject.pierced = 0;
				LOGGER.warn("Cock piercing was undefined, set to {0}", relativeRootObject.pierced);
			}
		}

		public function currentSerializationVerison():int
		{
			return SERIALIZATION_VERSION;
		}
	}
}


code:
package classes
{
	import classes.Enum;

	public class CockTypesEnum extends Enum
	{
		{initEnum(CockTypesEnum);}

		/* Cock types
		 * 0 - human
		 * 1 - horse
		 * 2 - dog
		 * 3 - demon
		 * 4 - tentacle?
		 * 5 - CAT
		 * 6 - Lizard/Naga?
		 * 7 - ANEMONE!
		 * 8 - ugliest wang ever (kangaroo)
		 * 9 - dragon
		 * 10 - displacer
		 * 11 - Fox

		 Group Types used for general description code (eventually)
		 * human  	- obvious
		 * mammal 	- obvious again
		 * super 	- supernatural types
		 * tentacle - only one tentacle!
		 * reptile	- make a guess
		 * seaworld - Anything in the water
		 * other	- doesn't fit anywhere else
		 */
		public static const HUMAN:CockTypesEnum = new CockTypesEnum("human");
		public static const HORSE:CockTypesEnum = new CockTypesEnum("mammal");
		public static const DOG:CockTypesEnum = new CockTypesEnum("mammal");
		public static const DEMON:CockTypesEnum = new CockTypesEnum("super");
		public static const TENTACLE:CockTypesEnum = new CockTypesEnum("tentacle");
		public static const CAT:CockTypesEnum = new CockTypesEnum("mammal");
		public static const LIZARD:CockTypesEnum = new CockTypesEnum("reptile");
		public static const ANEMONE:CockTypesEnum = new CockTypesEnum("seaworld");
		public static const KANGAROO:CockTypesEnum = new CockTypesEnum("mammal");
		public static const DRAGON:CockTypesEnum = new CockTypesEnum("reptile");
		public static const DISPLACER:CockTypesEnum = new CockTypesEnum("other");
		public static const FOX:CockTypesEnum = new CockTypesEnum("mammal");
		public static const BEE:CockTypesEnum = new CockTypesEnum("insect");
		public static const PIG:CockTypesEnum = new CockTypesEnum("mammal");
		public static const AVIAN:CockTypesEnum = new CockTypesEnum("avian");
		public static const RHINO:CockTypesEnum = new CockTypesEnum("mammal");
		public static const ECHIDNA:CockTypesEnum = new CockTypesEnum("mammal");
		public static const WOLF:CockTypesEnum = new CockTypesEnum("mammal");
		public static const RED_PANDA:CockTypesEnum = new CockTypesEnum("mammal");
		public static const FERRET:CockTypesEnum = new CockTypesEnum("mammal");
		public static const UNDEFINED:CockTypesEnum = new CockTypesEnum("");

		function CockTypesEnum(i_group:String = "") { _group = i_group; }
		private var _group:String;

		public function get Group():String
		{
			return _group;
		}

		public static function ParseConstant(i_constantName:String, i_caseSensitive:Boolean = false):CockTypesEnum
		{
			return CockTypesEnum(Enum.ParseConstant(CockTypesEnum, i_constantName, i_caseSensitive));
		}

		public static function ParseConstantByIndex(i_constantIndex:int = 0):CockTypesEnum
		{
			return CockTypesEnum(Enum.ParseConstantByIndex(CockTypesEnum, i_constantIndex));
		}

	}
}