code:
package classes
{
	import classes.GlobalFlags.kFLAGS;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.Items.*;
	import classes.Scenes.Camp;
	import classes.Scenes.Combat.Combat;
	import classes.Scenes.Places.Ingnam;
	import classes.Scenes.Places.Prison;
	import classes.Scenes.Dungeons.D3.D3;
	import classes.Scenes.Inventory;
	import classes.internals.Utils;

	import coc.model.GameModel;
	import coc.model.TimeModel;
	import coc.view.MainView;
	/**
	 * Quick hacky method to wrap new content in a class-based structure
	 * BaseContent acts as an access wrapper around CoC, enabling children of BaseContent to interact with
	 * function instances/properties of CoC in the same manner older content does with the minimal amount
	 * of modification.
	 * Also this means we might start being able to get IDE autocomplete shit working again! Huzzah!
	 * @author Gedan
	 */
	public class BaseContent extends Utils
	{
		// TODO remove when we have proper enums for this
		include "../../includes/appearanceDefs.as";

		public function BaseContent()
		{

		}
		protected function getGame():CoC
		{
			return kGAMECLASS;
		}

		protected function cheatTime(time:Number, needNext:Boolean = false):void
		{
			kGAMECLASS.cheatTime(time, needNext);
		}

		protected function get output():Output
		{
			return kGAMECLASS.output;
		}

		protected function get measurements():Measurements
		{
			return kGAMECLASS.measurements;
		}

		protected function get timeQ():Number
		{
			return kGAMECLASS.timeQ;
		}

		protected function get camp():Camp {
			return kGAMECLASS.camp;
		}

		protected function get ingnam():Ingnam {
			return kGAMECLASS.ingnam;
		}

		protected function get prison():Prison {
			return kGAMECLASS.prison;
		}

		protected function get d3():D3 {
			return kGAMECLASS.d3;
		}

		protected function get combat():Combat
		{
			return kGAMECLASS.combat;
		}

		protected function get mutations():Mutations
		{
			return kGAMECLASS.mutations;
		}

		public function goNext(time:Number,defNext:Boolean):Boolean
		{
			return kGAMECLASS.goNext(time,defNext);
		}

		protected function awardAchievement(title:String, achievement:*, display:Boolean = true, nl:Boolean = false, nl2:Boolean = true):void
		{
			return kGAMECLASS.awardAchievement(title, achievement, display, nl, nl2);
		}

		//SEASONAL EVENTS!
		protected function isHalloween():Boolean {
			return kGAMECLASS.fera.isItHalloween();
		}

		protected function isValentine():Boolean {
			return kGAMECLASS.valentines.isItValentine();
		}

		protected function isHolidays():Boolean {
			return kGAMECLASS.xmas.isItHolidays();
		}

		protected function isEaster():Boolean {
			return kGAMECLASS.plains.bunnyGirl.isItEaster();
		}

		protected function isThanksgiving():Boolean {
			return kGAMECLASS.thanksgiving.isItThanksgiving();
		}

		protected function isAprilFools():Boolean {
			return kGAMECLASS.aprilFools.isItAprilFools();
		}

		protected function get date():Date
		{
			return kGAMECLASS.date;
		}

		//Curse you, CoC updates!
		protected function get inDungeon():Boolean
		{
			return kGAMECLASS.inDungeon;
		}
		protected function set inDungeon(v:Boolean):void
		{
			kGAMECLASS.inDungeon = v;
		}

		protected function get inRoomedDungeon():Boolean
		{
			return kGAMECLASS.inRoomedDungeon;
		}
		protected function set inRoomedDungeon(v:Boolean):void
		{
			kGAMECLASS.inRoomedDungeon = v;
		}

		protected function get inRoomedDungeonResume():Function
		{
			return kGAMECLASS.inRoomedDungeonResume;
		}
		protected function set inRoomedDungeonResume(v:Function):void
		{
			kGAMECLASS.inRoomedDungeonResume = v;
		}

		/** Displays the sprite on the lower-left corner. */
		protected function spriteSelect(choice:Number = 0):void
		{
			kGAMECLASS.spriteSelect(choice);
		}

		/** Refreshes the stats panel. */
		protected function statScreenRefresh():void
		{
			kGAMECLASS.statScreenRefresh();
		}

		/** Displays the stats panel. */
		protected function showStats():void
		{
			kGAMECLASS.showStats();
		}

		/** Hide the stats panel. */
		protected function hideStats():void
		{
			kGAMECLASS.hideStats();
		}

		/** Hide the up/down arrows. */
		protected function hideUpDown():void
		{
			kGAMECLASS.hideUpDown();
		}

		/** Create a function that will pass one argument. */
		protected function createCallBackFunction(func:Function, arg:*):Function
		{
			return kGAMECLASS.createCallBackFunction(func,arg);
		}

		/** Create a function that will pass multiple arguments.
		 * @deprecated	This function is deprecated.
		 */
		protected function createCallBackFunction2(func:Function, ...args):Function
		{
			return kGAMECLASS.createCallBackFunction2.apply(null,[func].concat(args));
		}

		protected function doSFWloss():Boolean {
			return kGAMECLASS.doSFWloss();
		}

		protected function showCredits():void {
			kGAMECLASS.creditsScreen();
		}

		/**
		 * Start a new combat.
		 * @param	monster_ The new monster to be initialized.
		 * @param	plotFight_ Determines if the fight is important. Also prevents randoms from overriding uniques.
		 */
		protected function startCombat(monster_:Monster,plotFight_:Boolean=false):void{
			kGAMECLASS.combat.beginCombat(monster_, plotFight_);
		}

		protected function startCombatImmediate(monster:Monster, _plotFight:Boolean = false):void
		{
			kGAMECLASS.combat.beginCombatImmediate(monster, _plotFight);
		}

		protected function displayHeader(text:String):void
		{
			kGAMECLASS.displayHeader(text);
		}

		// Needed in a few rare cases for dumping text coming from a source that can't properly escape it's brackets
		// (Mostly traceback printing, etc...)
		protected function rawOutputText(output:String, purgeText:Boolean = false):void
		{
			kGAMECLASS.rawOutputText(output, purgeText);
		}

		protected function outputText(output:String, purgeText:Boolean = false, parseAsMarkdown:Boolean = false):void
		{
			kGAMECLASS.outputText(output, purgeText, parseAsMarkdown);
		}

		protected function clearOutput():void
		{
			kGAMECLASS.currentText = "";
			kGAMECLASS.mainView.clearOutputText();
		}

		protected function flushOutputTextToGUI():void {
			kGAMECLASS.flushOutputTextToGUI();
		}

		protected function doNext(eventNo:Function):void //Now typesafe
		{
			kGAMECLASS.doNext(eventNo);
		}

		protected function menu():void
		{
			kGAMECLASS.menu();
		}

		protected function hideMenus():void
		{
			kGAMECLASS.hideMenus();
		}

		/** Creates a menu with 10 buttons.
		 * @deprecated	This is deprecated. Use a series of addButton instead.
		 */
		protected function choices(text1:String, butt1:Function,
								text2:String, butt2:Function,
								text3:String, butt3:Function,
								text4:String, butt4:Function,
								text5:String, butt5:Function,
								text6:String, butt6:Function,
								text7:String, butt7:Function,
								text8:String, butt8:Function,
								text9:String, butt9:Function,
								text0:String, butt0:Function):void { //Now typesafe
			kGAMECLASS.choices(
					text1, butt1,
					text2, butt2,
					text3, butt3,
					text4, butt4,
					text5, butt5,
					text6, butt6,
					text7, butt7,
					text8, butt8,
					text9, butt9,
					text0, butt0
			);
		}

		/** Creates a menu with 5 buttons.
		 * @deprecated	This is deprecated. Use a series of addButton instead.
		 */
		protected function simpleChoices(text1:String, butt1:Function,
								text2:String, butt2:Function,
								text3:String, butt3:Function,
								text4:String, butt4:Function,
								text5:String, butt5:Function):void { //Now typesafe
			kGAMECLASS.simpleChoices(text1, butt1,
					text2, butt2,
					text3, butt3,
					text4, butt4,
					text5, butt5);
		}

		protected function doYesNo(eventYes:Function, eventNo:Function):void { //Now typesafe
			kGAMECLASS.doYesNo(eventYes, eventNo);
		}

		protected function addButton(pos:int, text:String = "", func1:Function = null, arg1:* = -9000, arg2:* = -9000, arg3:* = -9000, toolTipText:String = "", toolTipHeader:String = ""):void
		{
			kGAMECLASS.addButton(pos, text, func1, arg1, arg2, arg3, toolTipText, toolTipHeader);
		}

		protected function addButtonDisabled(pos:int, text:String = "", toolTipText:String = "", toolTipHeader:String = ""):void
		{
			kGAMECLASS.addButtonDisabled(pos, text, toolTipText, toolTipHeader);
		}

		protected function removeButton(arg:*):void
		{
			kGAMECLASS.removeButton(arg);
		}

		protected function hasButton(arg:*):Boolean
		{
			return kGAMECLASS.hasButton(arg);
		}

		protected function openURL(url:String):void{
			return kGAMECLASS.openURL(url);
		}

		/**
		 * Apply statmods to the player. dynStats wraps the regular stats call, but supports "named" arguments of the form:
		 * 		"statname", value.
		 * Exclusively supports either long or short stat names with a single call.
		 * "str", "lib" "lus", "cor" etc
		 * "strength, "libido", lust", "corruption"
		 * Specify the stat you wish to modify and follow it with the value.
		 * Separate each stat and value with a comma, and each stat/value pair, again, with a comma.
		 * eg: dynStats("str", 10, "lust" -100); will add 10 to str and subtract 100 from lust
		 * Also support operators could be appended with + - * /=
		 * eg: dynStats("str+", 1, "tou-", 2, "spe*", 1.1, "int/", 2, "cor=", 0)
		 *     will add 1 to str, subtract 2 from tou, increase spe by 10%, decrease int by 50%, and set cor to 0
		 *
		 * @param	... args
		 */
		protected function dynStats(... args):void
		{
			// Bullshit to unroll the incoming array
			kGAMECLASS.dynStats.apply(null, args);
		}

		protected function silly():Boolean
		{
			return kGAMECLASS.silly();
		}

		protected function HPChange(changeNum:Number,display:Boolean):void
		{
			kGAMECLASS.HPChange(changeNum,display);
		}

		protected function playerMenu():void { kGAMECLASS.playerMenu(); }

		protected function get player():Player
		{
			return kGAMECLASS.player;
		}

		protected function set player(val:Player):void
		{
			kGAMECLASS.player = val;
		}

		protected function get player2():Player
		{
			return kGAMECLASS.player2;
		}

		protected function set player2(val:Player):void
		{
			kGAMECLASS.player2 = val;
		}

		protected function get debug():Boolean
		{
			return kGAMECLASS.debug;
		}

		protected function set debug(val:Boolean):void
		{
			kGAMECLASS.debug = val;
		}

		protected function get ver():String
		{
			return kGAMECLASS.ver;
		}

		protected function set ver(val:String):void
		{
			kGAMECLASS.ver = val;
		}

		protected function get images():ImageManager
		{
			return kGAMECLASS.images;
		}

		protected function set images(val:ImageManager):void
		{
			kGAMECLASS.images = val;
		}

		protected function get monster():Monster
		{
			return kGAMECLASS.monster;
		}

		protected function set monster(val:Monster):void
		{
			kGAMECLASS.monster = val;
		}

		protected function get consumables():ConsumableLib{
			return kGAMECLASS.consumables;
		}
		protected function get useables():UseableLib{
			return kGAMECLASS.useables;
		}
		protected function get weapons():WeaponLib{
			return kGAMECLASS.weapons;
		}
		protected function get armors():ArmorLib{
			return kGAMECLASS.armors;
		}
		protected function get jewelries():JewelryLib{
			return kGAMECLASS.jewelries;
		}
		protected function get shields():ShieldLib{
			return kGAMECLASS.shields;
		}
		protected function get undergarments():UndergarmentLib{
			return kGAMECLASS.undergarments;
		}
		protected function get inventory():Inventory{
			return kGAMECLASS.inventory;
		}

		protected function get time():TimeModel
		{
			return kGAMECLASS.time;
		}

		protected function set time(val:TimeModel):void
		{
			kGAMECLASS.time = val;
		}

		protected function get temp():int
		{
			return kGAMECLASS.temp;
		}

		protected function set temp(val:int):void
		{
			kGAMECLASS.temp = val;
		}

		protected function get args():Array
		{
			return kGAMECLASS.args;
		}

		protected function set args(val:Array):void
		{
			kGAMECLASS.args = val;
		}

		protected function get funcs():Array
		{
			return kGAMECLASS.funcs;
		}

		protected function set funcs(val:Array):void
		{
			kGAMECLASS.funcs = val;
		}

		protected function get mainView():MainView
		{
			return kGAMECLASS.mainView;
		}

		protected function set mainView(val:*):void
		{
			kGAMECLASS.mainView = val;
		}

		protected function get model():GameModel
		{
			return kGAMECLASS.model;
		}

		protected function set model(val:GameModel):void
		{
			kGAMECLASS.model = val;
		}

		protected function get flags():DefaultDict
		{
			return kGAMECLASS.flags;
		}

		protected function set flags(val:DefaultDict):void
		{
			kGAMECLASS.flags = val;
		}

		protected function get achievements():DefaultDict
		{
			return kGAMECLASS.achievements;
		}

		protected function set achievements(val:DefaultDict):void
		{
			kGAMECLASS.achievements = val;
		}

		protected function showStatDown(arg:String):void
		{
			kGAMECLASS.mainView.statsView.showStatDown(arg);
		}

		protected function showStatUp(arg:String):void
		{
			kGAMECLASS.mainView.statsView.showStatUp(arg);
		}

		protected function buttonTextIsOneOf(index:int, possibleLabels:Array):Boolean {
			return kGAMECLASS.buttonTextIsOneOf(index, possibleLabels);
		}

		protected function getButtonText(index:int):String {
			return kGAMECLASS.getButtonText(index);
		}

		protected function buttonIsVisible(index:int):Boolean {
			return kGAMECLASS.buttonIsVisible(index);
		}

		/**
		 * PRIMO BULLSHIT FUNCTION ACCESS
		 */
		// Need to work out a better way of doing this -- I THINK maybe treating external functions as a string and calling
		// addButton like "addButton(0, "thing", "thisFunc");" might be a way to do it -- check if Func var is a Func type in this.addbutton args
		// if it is, pass it into kGAMECLASS, if it isn't, check if string. If it is, use the string to pull the func from kGAMECLASS
		// before passing it into addbutton etc.
		// Going the string route also makes it... not awful to call into other content classes too - split string on . and chain
		// lookups into objects ie "umasShop.firstVisitPart1" -> kGAMECLASS["umasShop"].["firstVisitPart1"]()
		// @aimozg: but kGAMECLASS.umasShop.firstVisistPart1 instead of String is compile-time safe.
		// Clearly this isn't going to fly long term, but it's... functional for now.

	}

}


code:
package classes
{
	import classes.GlobalFlags.kGAMECLASS;
	import classes.GlobalFlags.kFLAGS;
	import coc.view.MainView;
	import flash.net.SharedObject;

	/**
	 * class to relocate ControlBindings-code into single method-calls
	 * @author Stadler76
	 */
	public class Bindings
	{
		public function get game():CoC { return kGAMECLASS; }
		public function get flags():DefaultDict { return game.flags; }

		public function Bindings() {}

		public function execQuickSave(slot:int):void
		{
			if (game.mainView.menuButtonIsVisible(MainView.MENU_DATA) && game.player.str > 0) {
				var doQuickSave:Function = function():void {
					game.mainView.nameBox.text = "";
					game.saves.saveGame("CoC_" + slot);
					game.outputText("Game saved to slot " + slot + "!", true);
					game.doNext(game.playerMenu);
				};
				if (flags[kFLAGS.DISABLE_QUICKSAVE_CONFIRM] != 0) {
					doQuickSave();
					return;
				}
				game.clearOutput();
				game.outputText("You are about to quicksave the current game to slot " + slot + "\n\nAre you sure?");
				game.menu();
				game.addButton(0, "No", game.playerMenu);
				game.addButton(1, "Yes", doQuickSave);
			}
		}

		public function execQuickLoad(slot:uint):void
		{
			if (game.mainView.menuButtonIsVisible(MainView.MENU_DATA)) {
				var saveFile:* = SharedObject.getLocal("CoC_" + slot, "/");
				var doQuickLoad:Function = function():void {
					if (game.saves.loadGame("CoC_" + slot)) {
						game.showStats();
						game.statScreenRefresh();
						game.outputText("Slot " + slot + " Loaded!", true);
						game.doNext(game.playerMenu);
					}
				};
				if (saveFile.data.exists) {
					if (game.player.str == 0 || flags[kFLAGS.DISABLE_QUICKLOAD_CONFIRM] != 0) {
						doQuickLoad();
						return;
					}
					game.clearOutput();
					game.outputText("You are about to quickload the current game from slot " + slot + "\n\nAre you sure?");
					game.menu();
					game.addButton(0, "No", game.playerMenu);
					game.addButton(1, "Yes", doQuickLoad);
				}
			}
		}
	}
}

license: unknown


code:
package classes
{
	/**
	 * Defines a container to wrap a closure around a game function, associating the callable object
	 * with a string name representation of the action undertaken, a description, and the associated
	 * keyCodes that the action is triggered by.
	 * The keyCodes are stored here primarily for ease of display, as we have a handy refernece for
	 * a displayable function name AND the actual keyCodes the function uses. The actual interface used
	 * for incoming key code -> do action is internal to the InputManager instance.
	 * @author Gedan
	 */
	public class BoundControlMethod
	{
		private var _funcToCall:Function;
		private var _shortName:String;
		private var _descript:String;

		private var _primaryKey:int;
		private var _secondaryKey:int;

		private var _index:int;

		/**
		 * Define a new bindable control method with "Unbound" keys.
		 *
		 * @param	func			The function closure used by this BoundControlMethod
		 * @param	name			The friendly name used for this BoundControlMethod
		 * @param	desc			A Description of what the BoundControlMethod does
		 * @param 	primaryKey		The primary bound key code
		 * @param	secondarykey 	The secondary bound key code
		 */
		public function BoundControlMethod(func:Function, name:String, desc:String, index:int, primaryKey:int = -1, secondaryKey:int = -1)
		{
			_funcToCall = func;
			_shortName = name;
			_descript = desc;
			_index = index;

			_primaryKey = primaryKey;
			_secondaryKey = secondaryKey;
		}

		/**
		 * Execute the wrapped BoundControlMethod. Uses an apply() call, so that arguments
		 * can be passed to the wrapped function.
		 * @param	... args	Args to pass to the wrapped function.
		 */
		public function ExecFunc(... args):void
		{
			_funcToCall.apply(null, args);
		}

		public function get Name():String
		{
			return _shortName;
		}

		public function get Description():String
		{
			return _descript;
		}

		public function get Func():Function
		{
			return _funcToCall;
		}

		public function get PrimaryKey():int
		{
			return _primaryKey;
		}

		public function set PrimaryKey(keyCode:int):void
		{
			_primaryKey = keyCode;
		}

		public function get SecondaryKey():int
		{
			return _secondaryKey;
		}

		public function set SecondaryKey(keyCode:int):void
		{
			_secondaryKey = keyCode;
		}

		public function get Index():int
		{
			return _index;
		}
	}

}


code:
package classes
{
	import classes.internals.Utils;

	public class BreastRowClass
	{
		//constructor
		public function BreastRowClass()
		{
		}
		public var breasts:Number = 2;
		public var nipplesPerBreast:Number = 1;
		public var breastRating:Number = 0;
		public var lactationMultiplier:Number = 0;
		//Fullness used for lactation....if 75 or greater warning bells start going off!
		//If it reaches 100 it reduces lactation multiplier.
		public var milkFullness:Number = 0;
		public var fullness:Number = 0;
		public var fuckable:Boolean = false;
		public var nippleCocks:Boolean = false;

		public function validate():String
		{
			var error:String = "";
			error += Utils.validateNonNegativeNumberFields(this, "BreastRowClass.validate", [
					"breasts", "nipplesPerBreast", "breastRating", "lactationMultiplier",
					"milkFullness", "fullness"
			]);
			return error;
		}
		/*
		0 - manchest
		1 - A cup
		2 - B cup
		3 - C cup
		4 - D cup
		5 - DD cup
		6 - E cup
		7 - F cup
		8 - G cup
		9 - GG cup
		10 - H
		11 - HH cup
		12 - HHH cup
		13 - beachball sized
		14 - ???*/
	}
}


code:
package classes
{
	import classes.internals.Utils;
	import classes.Appearance;
	import classes.CoC;
	import classes.SaveAwareInterface;

	public class BreastStore extends Utils implements SaveAwareInterface
	{
		private static const MAX_FLAG_VALUE:int				= 2999;
		private static const BREAST_STORE_VERSION_1:String	= "1";
		private static const LACTATION_BOOST:Array          = [0, 0, 2, 3, 6, 9, 17]; //Disabled, None, Light, Moderate, Strong, Heavy, Epic

		public static const LACTATION_DISABLED:int			= 0;
		public static const LACTATION_NONE:int				= 1; //Full == (>= 50), Overfull == (>= 60 + 5 * _lactationLevel), Overload == (>= 60 + 20 * _lactationLevel)
		public static const LACTATION_LIGHT:int				= 2; //Full after 25 hours, overfull after 35 hours, overloaded after 50 hours
		public static const LACTATION_MODERATE:int			= 3; //Full after 17 hours, overfull after 25 hours, overloaded after 40 hours
		public static const LACTATION_STRONG:int			= 4; //Full after  9 hours, overfull after 15 hours, overloaded after 30 hours
		public static const LACTATION_HEAVY:int				= 5; //Full after  6 hours, overfull after 12 hours, overloaded after 27 hours
		public static const LACTATION_EPIC:int				= 6; //Full after  3 hours, overfull after  9 hours, overloaded after 24 hours

		private var _breastFlag:int;
		private var _cupSize:int							= 0;
		private var _fullness:int							= 0; //How much milk the breasts currently hold - use milkQuantity to decide how much milk is produced in a scene
																	//The milkIsFull and milkIsOverflowing functions let you know how much the NPC wants to be milked
		private var _lactation:int							= 0; //How fast the breasts refill with milk
		private var _nippleLength:Number					= 0;
		private var _timesMilked:int						= 0; //How many times has this NPC been milked - only used internally
		private var _rows:int								= 0; //Number of rows of breasts. All assumed to be the same size

		public var preventLactationIncrease:int				= 0; //Control the points at which the lactation stops increasing or decreasing
		public var preventLactationDecrease:int				= 0;

		public function BreastStore(breastFlag:int) {
			_breastFlag = breastFlag;
			if (_breastFlag < 1 || _breastFlag > MAX_FLAG_VALUE) trace("Error: BreastStore created with invalid flag value. BreastStore(" + breastFlag + ")");
		}

		//Implementation of SaveAwareInterface
		public function updateAfterLoad(game:CoC):void {
			if (_breastFlag < 1 || _breastFlag > MAX_FLAG_VALUE) return;
			var flagData:Array = String(game.flags[_breastFlag]).split("^");
			if (flagData.length < 9) {
				//Loading from a file that doesn't contain appropriate save data.
				//Values will either have to be assigned in Saves.unFuckSave() or by the first encounter with this NPC
				return;
			}
			//For now there's no need to check the version. If this class is ever updated to save more the version will become useful.
			rows						= int(flagData[1]);
			cupSize						= int(flagData[2]);
			lactationLevel				= int(flagData[3]);
			nippleLength				= Number(flagData[4]);
			_fullness					= int(flagData[5]);
			_timesMilked				= int(flagData[6]);
			preventLactationIncrease	= int(flagData[7]);
			preventLactationDecrease	= int(flagData[8]);
		}

		public function updateBeforeSave(game:CoC):void {
			if (_breastFlag < 1 || _breastFlag > MAX_FLAG_VALUE) return;
			game.flags[_breastFlag] = BREAST_STORE_VERSION_1 + "^" + rows + "^" + cupSize + "^" + lactationLevel + "^" + nippleLength + "^" + _fullness + "^" + _timesMilked
				+ "^" + preventLactationIncrease + "^" + preventLactationDecrease;
		}
		//End of Interface Implementation

		public static function breastDescript(size:int, lactation:Number = 0):String {
			if (size < 1) return "flat breasts";
			var descript:String = (rand(2) == 0 ? Appearance.breastSize(size) : ""); //Add a description of the breast size 50% of the time
			switch (rand(10)) {
				case 1:
					if (lactation > 2) return descript + "milk-udders";
					break;
				case 2:
					if (lactation > 1.5) descript += "milky ";
					if (size > 4) return descript + "tits";
					break;
				case 4:
				case 5:
				case 6:
					return descript + "tits";
				case 7:
					if (lactation >= 2.5) return descript + "udders";
					if (lactation >= 1) descript += "milk ";
					return descript + "jugs";
				case 8:
					if (size > 6) return descript + "love-pillows";
					return descript + "boobs";
				case 9:
					if (size > 6) return descript + "tits";
				default:
			}
			return descript + "breasts";
		}

		public function get cupSize():int { return _cupSize; }

		public function set cupSize(value:int):void {
			if (value < CoC.BREAST_CUP_FLAT) value = CoC.BREAST_CUP_FLAT;
			if (value > CoC.BREAST_CUP_ZZZ_LARGE) value = CoC.BREAST_CUP_ZZZ_LARGE;
			_cupSize = value;
		}

		public function get lactationLevel():int { return _lactation; }

		public function set lactationLevel(value:int):void {
			if (value < LACTATION_DISABLED) value = LACTATION_DISABLED;
			if (value > LACTATION_EPIC) value = LACTATION_EPIC;
			if (_lactation <= LACTATION_NONE && value >= LACTATION_LIGHT) { //Lactation is just starting - zero the other vars involved
				_fullness = 0;
				_timesMilked = 0;
			}
			_lactation = value;
		}

		public function advanceTime():void {
			if (_lactation <= LACTATION_NONE) return;
			//Add to breastFullness and possibly adjust lactationLevel. Even when lactationLevel == LACTATION_NONE this is still doing something useful, adjusting _breastTimesMilked
			_fullness += LACTATION_BOOST[_lactation]; //Higher lactation means faster refill
			if (_fullness > 60 + 20 * LACTATION_BOOST[_lactation]) { //100 at LACTATION_LIGHT, 180 at LACTATION_EPIC - fullness over this value is overloaded, lactation may be reduced
				_fullness = 50; //This way fullness won't immediately hit the limit again
				if (_timesMilked >= 5) {
					_timesMilked -= 5; //If enough milkings have occured then don't reduce lactation level right away
				}
				else if (preventLactationDecrease != _lactation) {
					_lactation--;
				}
			}
		}

		public function adj():String {
			switch (_cupSize) {
				case CoC.BREAST_CUP_FLAT:		return "non-existent";
				case CoC.BREAST_CUP_A:			return "small";
				case CoC.BREAST_CUP_B:
				case CoC.BREAST_CUP_C:			return "palmable";
				case CoC.BREAST_CUP_D:
				case CoC.BREAST_CUP_DD:
				case CoC.BREAST_CUP_DD_BIG:		return "sizeable";
				case CoC.BREAST_CUP_E:
				case CoC.BREAST_CUP_E_BIG:
				case CoC.BREAST_CUP_EE:
				case CoC.BREAST_CUP_EE_BIG:
				case CoC.BREAST_CUP_F:
				case CoC.BREAST_CUP_F_BIG:
				case CoC.BREAST_CUP_FF:
				case CoC.BREAST_CUP_FF_BIG:		return "huge";
				case CoC.BREAST_CUP_G:
				case CoC.BREAST_CUP_G_BIG:
				case CoC.BREAST_CUP_GG:
				case CoC.BREAST_CUP_GG_BIG:
				case CoC.BREAST_CUP_H:
				case CoC.BREAST_CUP_H_BIG:
				case CoC.BREAST_CUP_HH:
				case CoC.BREAST_CUP_HH_BIG:
				case CoC.BREAST_CUP_I:
				case CoC.BREAST_CUP_I_BIG:
				case CoC.BREAST_CUP_II:
				case CoC.BREAST_CUP_II_BIG:		return "gigantic";
				case CoC.BREAST_CUP_J:
				case CoC.BREAST_CUP_J_BIG:
				case CoC.BREAST_CUP_JJ:
				case CoC.BREAST_CUP_JJ_BIG:
				case CoC.BREAST_CUP_K:
				case CoC.BREAST_CUP_K_BIG:
				case CoC.BREAST_CUP_KK:
				case CoC.BREAST_CUP_KK_BIG:
				case CoC.BREAST_CUP_L:
				case CoC.BREAST_CUP_L_BIG:
				case CoC.BREAST_CUP_LL:
				case CoC.BREAST_CUP_LL_BIG:
				case CoC.BREAST_CUP_M:
				case CoC.BREAST_CUP_M_BIG:
				case CoC.BREAST_CUP_MM:
				case CoC.BREAST_CUP_MM_BIG:
				case CoC.BREAST_CUP_MMM:
				case CoC.BREAST_CUP_MMM_LARGE:	return "mammoth";
				default:
			}
			return("titanic");
		}

		public function canTitFuck():Boolean { return _cupSize >= CoC.BREAST_CUP_C; }

		public function cup():String { return Appearance.breastCup(_cupSize); } //The cup size alone

		public function description(useAdj:Boolean = false, isMale:Boolean = false):String {
			if (_cupSize == CoC.BREAST_CUP_FLAT) return "flat" + (isMale ? " manly," : "") + " chest";
			return (useAdj ? adj() + " " : "") + cup() + " breasts";
		}

		public function breastDesc():String {
			return breastDescript(cupSize, 0.5 * lactationLevel);
		}

		public function hasBreasts():Boolean { return _cupSize != CoC.BREAST_CUP_FLAT; }

		public function lactating():Boolean { return _lactation >= LACTATION_LIGHT; }

		public function milked():Boolean { //Returns true if this milking increased the NPC's lactationLevel
			_fullness = 0;
			_timesMilked++;
			if (preventLactationIncrease == _lactation) return false;
			switch (_lactation) { //With enough milking the lactation level increases
				case LACTATION_NONE: //If you suckle enough times the NPC will eventually start producing milk if they're set to LACTATION_NONE
					if (_timesMilked < 12) return false;
					break;
				case LACTATION_LIGHT:
					if (_timesMilked < 10) return false;
					break;
				case LACTATION_MODERATE:
					if (_timesMilked < 12) return false;
					break;
				case LACTATION_HEAVY:
					if (_timesMilked < 15) return false;
					break;
				case LACTATION_STRONG:
					if (_timesMilked < 20) return false;
					break;
				default: //No amount of suckling will increase lactation levels for this NPC
					return false;
			}
			//Only reach this point if the NPC has been milked enough times to justify increasing their milk production
			_timesMilked = 5;
			lactationLevel++;
			return true;
		}

		public function milkIsFull():Boolean { return (_lactation <= LACTATION_NONE ? 0 : _fullness >= 50); }

		public function milkIsOverflowing():Boolean {
			return (_lactation <= LACTATION_NONE ? 0 : _fullness >= 60 + 5 * LACTATION_BOOST[_lactation]); //Probably pretty desperate to be milked by this point
		}

		//At fullness == 50 the maximum amount of milk is produced. When overfull, lactation level is reduced and fullness drops to 50.
		//So a higher lactationLevel means more milk is produced and the breasts can stay full without drying up for longer. Will always return 0 if not lactating
		public function milkQuantity():Number
		{
			if (_lactation <= LACTATION_NONE) return 0;
			return 0.01 * Math.max(100, 2 * _fullness) * Number(20 * _rows * _cupSize * (_lactation - 1));
		}

		public function nippleDescript(tiny:String = "tiny", small:String = "prominent", large:String = "large", huge:String = "elongated", massive:String = "massive"):String
		{
			if (_nippleLength < 3) return tiny;
			if (_nippleLength < 10) return small;
			if (_nippleLength < 20) return large;
			if (_nippleLength < 32) return huge;
			return massive;
		}

		public function get nippleLength():Number { return _nippleLength; }

		public function set nippleLength(value:Number):void {
			if (value < 0) value = 0;
			_nippleLength = 0.1 * Math.round(10 * value); //Ensure nipple length only goes to one decimal place
		}

		public function get rows():int { return _rows; }

		public function set rows(value:int):void {
			if (value < 1) value = 1;
			_rows = value;
		}
	}
}