code:
package classes
{
	import classes.*;
	import classes.GlobalFlags.*;
	import classes.Items.*;
	import classes.Scenes.*;
	import classes.Scenes.Seasonal.Seasons;
	import classes.Scenes.Combat.*;
	import classes.Scenes.Dungeons.LethicesKeep.*;
	import classes.Scenes.Places.*;
	import classes.internals.*;
	import coc.view.*;
	import classes.internals.RootCounters;
	import flash.sampler.NewObjectSample;
/**
	 * 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 {

		//Gender constants
		protected const ANYGENDER:int = -1;
		protected const NOGENDER:int = 0;
		protected const MALE:int = 1;
		protected const FEMALE:int = 2;
		protected const HERM:int = 3;

		public function BaseContent() {

		}

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

		protected function get output():Output {
			return game.output;
		}
		/*
		protected function get credits():Credits
		{
			return game.credits;
		}
		*/
		protected function get timeQ():Number {
			return game.timeQ;
		}

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

		protected function get cabin():Cabin {
			return game.cabin;
		}

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

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

		protected function get lethicesKeep():LethicesKeep {
			return game.lethicesKeep;
		}

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

		protected function get combatAttackData():CombatAttackData {
			return game.combatAttackData;
		}

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

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

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

		protected function unlockCodexEntry(codexEntry:int, nlBefore:Boolean = true, nlAfter:Boolean = false):void {
			return game.unlockCodexEntry(codexEntry, nlBefore, nlAfter);
		}

		protected function get npcOptions():Object {
			return game.gameSettings.npcSettings;
		}

		protected function addictionEnabled():Boolean {
			return game.addictionEnabled();
		}

		//Putting this here for easy access because Urta is fucking everywhere
		protected function get urtaDisabled():Boolean {
			return game.urtaDisabled;
		}

		//SEASONAL EVENTS!
		protected function isHalloween(strict:Boolean = false):Boolean {
			return game.seasons.isItHalloween(strict);
		}

		protected function isValentine(strict:Boolean = false):Boolean {
			return game.seasons.isItValentine(strict);
		}

		protected function isSaturnalia(strict:Boolean = false):Boolean {
			return game.seasons.isItSaturnalia(strict);
		}

		protected function isEaster():Boolean {
			return game.seasons.isItEaster();
		}

		protected function isThanksgiving():Boolean {
			return game.seasons.isItThanksgiving();
		}

		protected function isAprilFools():Boolean {
			return game.seasons.isItAprilFools();
		}

		protected function isWinter(strict:Boolean = false):Boolean {
			return game.seasons.isItWinter(strict);
		}

		protected function isSpring(strict:Boolean = false):Boolean {
			return game.seasons.isItSpring(strict);
		}

		protected function isSummer(strict:Boolean = false):Boolean {
			return game.seasons.isItSummer(strict);
		}

		protected function isAutumn(strict:Boolean = false):Boolean {
			return game.seasons.isItAutumn(strict);
		}

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

		//Curse you, CoC updates!
		protected function get inDungeon():Boolean {
			return game.inDungeon;
		}

		protected function set inDungeon(v:Boolean):void {
			game.inDungeon = v;
		}

		protected function get inRoomedDungeon():Boolean {
			return game.inRoomedDungeon;
		}

		protected function set inRoomedDungeon(v:Boolean):void {
			game.inRoomedDungeon = v;
		}

		protected function get inRoomedDungeonResume():Function {
			return game.inRoomedDungeonResume;
		}

		protected function set inRoomedDungeonResume(v:Function):void {
			game.inRoomedDungeonResume = v;
		}

		protected function get inRoomedDungeonName():String
		{
			return game.inRoomedDungeonName;
		}
		protected function set inRoomedDungeonName(v:String):void
		{
			game.inRoomedDungeonName = v;
		}

		/**
		 * Displays the sprite on the lower-left corner.
		 * Can accept frame index or SpriteDb.s_xxx (class extends Bitmap)
		 * */
		protected function spriteSelect(choice:Object = 0):void{
			game.spriteSelect(choice);
		}

		/** Displays images anywhere*/
		protected function imageSelect(choice:Object = 0, x:int = 0, y:int = 0):void{
			game.imageSelect(choice, x, y);
		}

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

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

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

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

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

		protected function createCallBackFunction2(func:Function, ...args):Function {
			return game.createCallBackFunction2.apply(null,[func].concat(args));
		}

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

		protected function isPeaceful():Boolean {
			return game.isPeaceful();
		}

		/**
		 * 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, showNext:Boolean = true):void {
			game.combat.beginCombat(monster_, plotFight_, showNext);
		}

		public function startCombatMultiple(monster_:Monster, monster_2:Monster, monster_3:Monster, monster_4:Monster,hpvictoryFunc_:Function,hplossFunc_:Function,lustvictoryFunc_:Function,lustlossFunc_:Function,description_:String = "", plotFight_:Boolean = false, showNext:Boolean = true):void {
			var array:Vector.<Monster> = new Vector.<Monster>();
			if (monster_ != null) array.push(monster_);
			if (monster_2 != null) array.push(monster_2);
			if (monster_3 != null) array.push(monster_3);
			if (monster_4 != null) array.push(monster_4);
			game.combat.beginCombatMultiple(array,hpvictoryFunc_,hplossFunc_,lustvictoryFunc_,lustlossFunc_,description_,plotFight_,showNext);
		}
		protected function startCombatImmediate(monster:Monster, _plotFight:Boolean = false):void {
			game.combat.beginCombat(monster, _plotFight, false);
		}

		protected function displayHeader(text:String):void {
			game.output.header(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(text:String):void{
			game.output.raw(text);
		}

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

		protected function clearOutput(clearAll:Boolean = true):void {
			if (clearAll) game.output.clear();
			else game.output.clearText();
		}

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

		/**
		 * Hides all bottom buttons.
		 *
		 * <b>Note:</b> Calling this with open formatting tags can result in strange behaviour,
		 * e.g. all text will be formatted instead of only a section.
		 */
		protected function menu():void
		{
			game.output.menu();
		}

		protected function generateMenu(buttonDataList:Array,returnFunc:Function = null, startIndex:int = 0):void{
			game.output.generateMenu(buttonDataList, returnFunc, startIndex);
		}

		protected function hideMenus():void {
			game.output.hideMenus();
		}

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

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

		protected function addNextButton(text:String = "", func1:Function = null, arg1:* = -9000, arg2:* = -9000, arg3:* = -9000, toolTipText:String = "", toolTipHeader:String = ""):CoCButton
		{
			return game.output.addNextButton(text, func1, arg1, arg2, arg3, toolTipText, toolTipHeader);
		}

		protected function addButtonDisabled(pos:int, text:String = "", toolTipText:String = "", toolTipHeader:String = ""):CoCButton
		{
			return game.output.addButtonDisabled(pos, text, toolTipText, toolTipHeader);
		}

		protected function addNextButtonDisabled(text:String = "", toolTipText:String = "", toolTipHeader:String = ""):CoCButton
		{
			return game.output.addNextButtonDisabled(text, toolTipText, toolTipHeader);
		}

		protected function addDisabledButton(pos:int, text:String = "", toolTipText:String = "", toolTipHeader:String = ""):CoCButton
		{
			return game.output.addButtonDisabled(pos, text, toolTipText, toolTipHeader);
		}

		public function setSexLeaveButton(func:Function = null, leaveText:String = "Leave",pos:int = 14,gender:int = -1,chanceBonus:int = 0):void {
			return game.setSexLeaveButton(func,leaveText,pos,gender,chanceBonus);
		}

		protected function button(pos:int):CoCButton
		{
			return game.output.button(pos);
		}

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

		protected function openURL(url:String):void {
			return game.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
		 * @return Object of (newStat-oldStat) with keys str, tou, spe, int, lib, sen, lus, cor
		 */
		protected function dynStats(... args):Object{
			// Bullshit to unroll the incoming array
			return game.dynStats.apply(null, args);
		}

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

		protected function noFur():Boolean {
			return game.noFur();
		}

		protected function playerMenu():void {
			game.mainMenu.hideMainMenu();
			game.playerMenu();
		}

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

		/**
		 * This is alias for player.
		 */
		protected function get pc():Player
		{
			return game.player;
		}

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

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

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

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

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

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

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

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

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

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

		/**
		 * This is alias for monster.
		 */
		protected function get enemy():Monster
		{
			return game.monster;
		}

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

		protected function get monsterArray():Vector.<Monster>{
			return game.monsterArray;
		}

		protected function set monsterArray(val:Vector.<Monster>):void{
			game.monsterArray = val.slice(0);
		}

		protected function get consumables():ConsumableLib {
			return game.consumables;
		}

		protected function get useables():UseableLib {
			return game.useables;
		}

		protected function get weapons():WeaponLib {
			return game.weapons;
		}

		protected function get armors():ArmorLib {
			return game.armors;
		}

		protected function get jewelries():JewelryLib {
			return game.jewelries;
		}

		protected function get shields():ShieldLib {
			return game.shields;
		}

		protected function get undergarments():UndergarmentLib {
			return game.undergarments;
		}

		protected function get inventory():Inventory {
			return game.inventory;
		}

		protected function get time():Time{
			return game.time;
		}

		protected function set time(val:Time):void{
			game.time = val;
		}

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

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

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

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

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

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

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

		protected function get mainViewManager():MainViewManager{
			return game.mainViewManager;
		}

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

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

		protected function get counters():RootCounters {
			return game.counters;
		}

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

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

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

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

		/**
		 * 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 game.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 slotX:String = "CoC_" + slot;
				if (flags[kFLAGS.HARDCORE_MODE] > 0) slotX = flags[kFLAGS.HARDCORE_SLOT];
				var doQuickSave:Function = function():void {
					game.mainView.nameBox.text = "";
					game.saves.saveGame(slotX);
					game.clearOutput();
					game.outputText("Game saved to " + slotX + "!");
					game.output.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 " + slotX + "\n\nAre you sure?");
				game.output.menu();
				game.output.addButton(0, "No", game.playerMenu);
				game.output.addButton(1, "Yes", doQuickSave);
			}
		}

		public function execQuickLoad(slot:uint):void
        {
			if ((game.mainView.menuButtonIsVisible(MainView.MENU_DATA) || flags[kFLAGS.QUICKLOAD_ANYWHERE_ENABLED]) && game.player.str > 0) {
				var saveFile:SharedObject = SharedObject.getLocal("CoC_" + slot, "/");
				if (!saveFile.data.exists) { return; }
				var doQuickLoad:Function = function():void {
					if (game.saves.loadGame("CoC_" + slot)) {
						game.output.showStats();
						game.output.statScreenRefresh();
						game.clearOutput();
						game.outputText("Slot " + slot + " Loaded!");
						game.output.doNext(game.playerMenu);
					}
				};
				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.output.menu();
					game.output.addButton(0, "No", game.playerMenu);
					game.output.addButton(1, "Yes", doQuickLoad);
			}
        }
	}
}

license: unknown


code:
package classes.BodyParts
{
	/**
	 * Container class for the players antennae
	 * @since November 08, 2017
	 * @author Stadler76
	 */
	public class Antennae
	{
		public static const NONE:int       =   0;
		public static const BEE:int        =   2;
		public static const COCKATRICE:int =   3;

		public var type:Number = NONE;

		public function restore():void
		{
			type = NONE;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	import classes.Creature;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.internals.Utils;

	/**
	 * Container class for the players arms
	 * @since November 07, 2017
	 * @author Stadler76
	 */
	public class Arms
	{
		public static const HUMAN:int      =   0;
		public static const HARPY:int      =   1;
		public static const SPIDER:int     =   2;
		public static const BEE:int        =   3;
		public static const PREDATOR:int   =   4;
		public static const SALAMANDER:int =   5;
		public static const WOLF:int       =   6;
		public static const COCKATRICE:int =   7;
		public static const RED_PANDA:int  =   8;
		public static const FERRET:int     =   9;
		public static const CAT:int        =  10;
		public static const DOG:int        =  11;
		public static const FOX:int        =  12;
		public static const DRAGON:int     =  13;
		public static const LIZARD:int     =  14;

		private var _creature:Creature;
		public var type:Number = HUMAN;
		public var claws:Claws = new Claws();

		public function Arms(i_creature:Creature = null)
		{
			_creature = i_creature;
		}

		public function setType(armType:Number, clawType:Number = Claws.NORMAL):void
		{
			type = armType;

			switch (armType) {
				case PREDATOR:   updateClaws(clawType);         break;
				case SALAMANDER: updateClaws(Claws.SALAMANDER); break;
				case COCKATRICE: updateClaws(Claws.COCKATRICE); break;
				case RED_PANDA:  updateClaws(Claws.RED_PANDA);  break;
				case FERRET:     updateClaws(Claws.FERRET);     break;
				case CAT:        updateClaws(Claws.CAT);        break;
				case DOG:        updateClaws(Claws.DOG);        break;
				case FOX:        updateClaws(Claws.FOX);        break;

				case HUMAN:
				case HARPY:
				case SPIDER:
				case BEE:
				case WOLF:
				default:         updateClaws(clawType);
			}
		}

		public function updateClaws(clawType:int = Claws.NORMAL):String
		{
			var clawTone:String = "";
			var oldClawTone:String = claws.tone;

			switch (clawType) {
				case Claws.DRAGON:     clawTone = "steel-gray"; break;
				case Claws.SALAMANDER: clawTone = "fiery-red";  break;
				case Claws.LIZARD:
					if (_creature === null)
						break;
					// See http://www.bergenbattingcenter.com/lizard-skins-bat-grip/ for all those NYI! lizard skin colors
					// I'm still not that happy with these claw tones. Any suggestion would be nice.
					switch (_creature.skin.tone) {
						case "red":         clawTone = "reddish";     break;
						case "green":       clawTone = "greenish";    break;
						case "white":       clawTone = "light-gray";  break;
						case "blue":        clawTone = "bluish";      break;
						case "black":       clawTone = "dark-gray";   break;
						case "purple":      clawTone = "purplish";    break;
						case "silver":      clawTone = "silvery";     break;
						case "pink":        clawTone = "pink";        break;
						case "orange":      clawTone = "orangey";     break;
						case "yellow":      clawTone = "yellowish";   break;
						case "desert-camo": clawTone = "pale-yellow"; break; // NYI!
						case "gray-camo":   clawTone = "gray";        break; // NYI!
						default:            clawTone = "gray";        break;
					}
					break;
				case Claws.IMP:
					if (_creature !== null)
						clawTone = _creature.skin.tone;
					break;
				default:
					clawTone = "";
			}

			claws.type = clawType;
			claws.tone = clawTone;

			return oldClawTone;
		}

		public function restore():void
		{
			type = HUMAN;
			claws.restore();
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
			if (p.hasOwnProperty('claws')) claws.setProps(p.claws);
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}

		public function adj():String {
			var text:String = "";
			switch (type) {
				case HARPY:
					text = Utils.randomChoice("feathered", "feathery");
					break;
				case SPIDER:
					text = "chitinous";
					break;
				case BEE:
					text = "chitinous";
					break;
				case SALAMANDER:
					text = Utils.randomChoice("scaled", "scaly");
					break;
				case WOLF:
					text = "furry";
					break;
				case COCKATRICE:
					text = "scaled and feathered";
					break;
				case RED_PANDA:
					text = "fluffy";
					break;
				case FERRET:
					text = Utils.randomChoice("fluffy", "furry");
					break;
				case CAT:
					text = "furry";
					break;
				case DOG:
					text = "furry";
					break;
				case FOX:
					text = "furry";
					break;
				case DRAGON:
					text = Utils.randomChoice("scaled", "scaly");
					break;
				case LIZARD:
					text = Utils.randomChoice("scaled", "scaly");
					break;
				case HUMAN:
				case PREDATOR:
				default:
			}
			return text;
		}

		public function phrase():String {
			var text:String = "arms";
			var adjective:String = adj();
			if (adjective != "") text = adjective + " " + text;
			return text;
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * ...
	 * @since August 06, 2017
	 * @author Stadler76
	 */
	public class BaseBodyPart
	{
		public static const COLOR_ID_MAIN:int = 1;
		public static const COLOR_ID_2ND:int  = 2;

		public function getColorDesc(id:int):String
		{
			return "";
		}

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

		public function hasDyeColor(_color:String):Boolean
		{
			return true;
		}

		public function applyDye(_color:String):void {}

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

		public function hasOilColor(_color:String):Boolean
		{
			return true;
		}

		public function applyOil(_color:String):void {}

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

		public function hasOil2Color(_color2:String):Boolean
		{
			return true;
		}

		public function applyOil2(_color2:String):void {}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players beard
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Beard
	{
		public static const NORMAL:int      =    0;
		public static const GOATEE:int      =    1;
		public static const CLEANCUT:int    =    2;
		public static const MOUNTAINMAN:int =    3;

		public var style:Number  = NORMAL;
		public var length:Number = 0;

		public function restore():void
		{
			style  = NORMAL;
			length = 0;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('style'))  style  = p.style;
			if (p.hasOwnProperty('length')) length = p.length;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players butt
	 * @since November 10, 2017
	 * @author Stadler76
	 */
	public class Butt
	{
		public static const RATING_BUTTLESS:int          =   0;
		public static const RATING_TIGHT:int             =   2;
		public static const RATING_AVERAGE:int           =   4;
		public static const RATING_NOTICEABLE:int        =   6;
		public static const RATING_LARGE:int             =   8;
		public static const RATING_JIGGLY:int            =  10;
		public static const RATING_EXPANSIVE:int         =  13;
		public static const RATING_HUGE:int              =  16;
		public static const RATING_INCONCEIVABLY_BIG:int =  20;

		public var rating:Number = RATING_BUTTLESS;
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players claws
	 * @since November 08, 2017
	 * @author Stadler76
	 */
	public class Claws
	{
		public static const NORMAL:int     =   0;
		public static const LIZARD:int     =   1;
		public static const DRAGON:int     =   2;
		public static const SALAMANDER:int =   3;
		public static const CAT:int        =   4;
		public static const DOG:int        =   5;
		public static const FOX:int        =   6;
		public static const MANTIS:int     =   7; // NYI! Placeholder for Xianxia mod
		public static const IMP:int        =   8;
		public static const COCKATRICE:int =   9;
		public static const RED_PANDA:int  =  10;
		public static const FERRET:int     =  11;

		public var type:Number = NORMAL;
		public var tone:String = "";

		public function restore():void
		{
			type = NORMAL;
			tone = "";
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
			if (p.hasOwnProperty('tone')) tone = p.tone;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players ears
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Ears
	{
		public static const HUMAN:int      =   0;
		public static const HORSE:int      =   1;
		public static const DOG:int        =   2;
		public static const COW:int        =   3;
		public static const ELFIN:int      =   4;
		public static const CAT:int        =   5;
		public static const LIZARD:int     =   6;
		public static const BUNNY:int      =   7;
		public static const KANGAROO:int   =   8;
		public static const FOX:int        =   9;
		public static const DRAGON:int     =  10;
		public static const RACCOON:int    =  11;
		public static const MOUSE:int      =  12;
		public static const FERRET:int     =  13;
		public static const PIG:int        =  14;
		public static const RHINO:int      =  15;
		public static const ECHIDNA:int    =  16;
		public static const DEER:int       =  17;
		public static const WOLF:int       =  18;
		public static const SHEEP:int      =  19;
		public static const IMP:int        =  20;
		public static const COCKATRICE:int =  21;
		public static const RED_PANDA:int  =  22;

		public var type:Number  = HUMAN;
		public var value:Number = 0;

		public function restore():void
		{
			type  = HUMAN;
			value = 0;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))  type  = p.type;
			if (p.hasOwnProperty('value')) value = p.value;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players eyes
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Eyes
	{
		public static const HUMAN:int                =   0;
		public static const FOUR_SPIDER_EYES:int     =   1; //DEPRECATED, USE Eyes.SPIDER AND EYECOUNT = 4
		public static const BLACK_EYES_SAND_TRAP:int =   2;
		public static const LIZARD:int               =   3;
		public static const DRAGON:int               =   4; // Slightly different description/TF and *maybe* in the future(!) grant different perks/combat abilities
		public static const BASILISK:int             =   5;
		public static const WOLF:int                 =   6;
		public static const SPIDER:int               =   7;
		public static const COCKATRICE:int           =   8;
		public static const CAT:int                  =   9;

		public var type:Number  = HUMAN;
		public var count:Number = 2;

		public function setType(eyeType:Number, eyeCount:Number = NaN):void
		{
			type = eyeType;

			if (!isNaN(eyeCount)) {
				count = eyeCount;
				return;
			}

			switch (eyeType) {
				case FOUR_SPIDER_EYES:
				case SPIDER:
					type = SPIDER; // Failsafe just in case ...
					count = 4;
					break;

				default:
					count = 2;
			}
		}

		public function restore():void
		{
			type  = HUMAN;
			count = 2;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))  type  = p.type;
			if (p.hasOwnProperty('count')) count = p.count;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	import classes.Creature;
	/**
	 * Container class for the players face
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Face
	{
		public static const HUMAN:int        =   0;
		public static const HORSE:int        =   1;
		public static const DOG:int          =   2;
		public static const COW_MINOTAUR:int =   3;
		public static const SHARK_TEETH:int  =   4;
		public static const SNAKE_FANGS:int  =   5;
		public static const CATGIRL:int      =   6;
		public static const LIZARD:int       =   7;
		public static const BUNNY:int        =   8;
		public static const KANGAROO:int     =   9;
		public static const SPIDER_FANGS:int =  10;
		public static const FOX:int          =  11;
		public static const DRAGON:int       =  12;
		public static const RACCOON_MASK:int =  13;
		public static const RACCOON:int      =  14;
		public static const BUCKTEETH:int    =  15;
		public static const MOUSE:int        =  16;
		public static const FERRET_MASK:int  =  17;
		public static const FERRET:int       =  18;
		public static const PIG:int          =  19;
		public static const BOAR:int         =  20;
		public static const RHINO:int        =  21;
		public static const ECHIDNA:int      =  22;
		public static const DEER:int         =  23;
		public static const WOLF:int         =  24;
		public static const COCKATRICE:int   =  25;
		public static const BEAK:int         =  26; // This is a placeholder for the next beaked face type, so feel free to refactor (rename)
		public static const RED_PANDA:int    =  27;
		public static const CAT:int          =  28;

		private var _creature:Creature;
		public var type:Number = HUMAN;

		public function Face(i_creature:Creature = null)
		{
			_creature = i_creature;
		}

		public function setType(faceType:Number, eyeType:Number = NaN):void
		{
			type = faceType;

			if (_creature === null) {
				return;
			}

			if (!isNaN(eyeType)) {
				_creature.eyes.setType(eyeType);
				return;
			}

			switch (faceType) {
				case Face.CAT:
				case Face.CATGIRL:
					_creature.eyes.setType(Eyes.CAT);
					break;

				default:
					// Empty default because SonarQQbe ...
			}
		}

		public function restore():void
		{
			type = HUMAN;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players gills
	 * @since November 07, 2017
	 * @author Stadler76
	 */
	public class Gills
	{
		public static const NONE:int    =   0;
		public static const ANEMONE:int =   1;
		public static const FISH:int    =   2;

		public var type:Number = NONE;

		public function restore():void
		{
			type = NONE;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players hair
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Hair
	{
		public static const NORMAL:int          =    0;
		public static const FEATHER:int         =    1;
		public static const GHOST:int           =    2;
		public static const GOO:int             =    3;
		public static const ANEMONE:int         =    4;
		public static const QUILL:int           =    5;
		public static const BASILISK_SPINES:int =    6;
		public static const BASILISK_PLUME:int  =    7;
		public static const WOOL:int            =    8;
		public static const LEAF:int			=	 9;
		public static const VINE:int			=   10;

		public var type:Number   	  = NORMAL;
		public var color:String  	  = "no";
		public var length:Number 	  = 0;
		public var adj:String		  = "";
		public var flowerColor:String = "";

		public function restore():void
		{
			type   = NORMAL;
			color  = "no";
			length = 0;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))   type   = p.type;
			if (p.hasOwnProperty('color'))  color  = p.color;
			if (p.hasOwnProperty('length')) length = p.length;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players hips
	 * @since November 10, 2017
	 * @author Stadler76
	 */
	public class Hips
	{
		public static const RATING_BOYISH:int         =   0;
		public static const RATING_SLENDER:int        =   2;
		public static const RATING_AVERAGE:int        =   4;
		public static const RATING_AMPLE:int          =   6;
		public static const RATING_CURVY:int          =  10;
		public static const RATING_FERTILE:int        =  15;
		public static const RATING_INHUMANLY_WIDE:int =  20;

		public var rating:Number = RATING_BOYISH;
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players ears
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Horns
	{
		public static const NONE:int                     =   0;
		public static const DEMON:int                    =   1;
		public static const COW_MINOTAUR:int             =   2;
		public static const DRACONIC_X2:int              =   3;
		public static const DRACONIC_X4_12_INCH_LONG:int =   4;
		public static const ANTLERS:int                  =   5;
		public static const GOAT:int                     =   6;
		public static const UNICORN:int                  =   7;
		public static const RHINO:int                    =   8;
		public static const SHEEP:int                    =   9;
		public static const RAM:int                      =  10;
		public static const IMP:int                      =  11;
		public static const WOODEN:int					 =  12;

		public var type:Number  = NONE;
		/** horns length or number depending on the type */
		public var value:Number = 0;

		public function restore():void
		{
			type  = NONE;
			value = 0;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))  type  = p.type;
			if (p.hasOwnProperty('value')) value = p.value;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players lowerbody
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class LowerBody
	{
		public static const HUMAN:int                 =   0;
		public static const HOOFED:int                =   1;
		public static const DOG:int                   =   2;
		public static const NAGA:int                  =   3;
		//public static const CENTAUR:int             =   4; //DEPRECATED - USE HOOFED + LEGCOUNT 4
		public static const DEMONIC_HIGH_HEELS:int    =   5;
		public static const DEMONIC_CLAWS:int         =   6;
		public static const BEE:int                   =   7;
		public static const GOO:int                   =   8;
		public static const CAT:int                   =   9;
		public static const LIZARD:int                =  10;
		public static const PONY:int                  =  11;
		public static const BUNNY:int                 =  12;
		public static const HARPY:int                 =  13;
		public static const KANGAROO:int              =  14;
		public static const CHITINOUS_SPIDER_LEGS:int =  15;
		public static const DRIDER:int                =  16;
		public static const FOX:int                   =  17;
		public static const DRAGON:int                =  18;
		public static const RACCOON:int               =  19;
		public static const FERRET:int                =  20;
		public static const CLOVEN_HOOFED:int         =  21;
		//public static const RHINO:int               =  22;
		public static const ECHIDNA:int               =  23;
		//public static const DEERTAUR:int            =  24; //DEPRECATED - USE CLOVEN HOOFED + LEGCOUNT 4
		public static const SALAMANDER:int            =  25;
		public static const WOLF:int                  =  26;
		public static const IMP:int                   =  27;
		public static const COCKATRICE:int            =  28;
		public static const RED_PANDA:int             =  29;
		public static const ROOT_LEGS:int			  =  30;

		public var type:Number     = HUMAN;
		public var legCount:Number = 2;
		public var incorporeal:Boolean = false;

		public function restore():void
		{
			type     = HUMAN;
			legCount = 2;
			incorporeal = false;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))     type     = p.type;
			if (p.hasOwnProperty('legCount')) legCount = p.legCount;
			if (p.hasOwnProperty('incorporeal')) incorporeal = p.incorporeal;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}

		public function skin():String {
			var text:String = "";
			switch(type) {
				case RED_PANDA:
				case WOLF:
				case FERRET:
				case FOX:
				case KANGAROO:
				case ECHIDNA:
				case BUNNY:
				case PONY:
				case CLOVEN_HOOFED:
				case DOG:
				case CAT:
				case RACCOON:
					text = "fur";
				case CHITINOUS_SPIDER_LEGS:
				case DRIDER:
				case BEE:
					text = "chitin";
				case HARPY:
				case COCKATRICE:
					text = "feathers";
				case HOOFED:
					text = "hide";
				case NAGA:
				case SALAMANDER:
				case DRAGON:
				case LIZARD:
					text = "scales";
					break;
				case ROOT_LEGS:
					text = "bark";
					break;
				case GOO:
					text = "goo";
				case HUMAN:
				case IMP:
				case DEMONIC_CLAWS:
				case DEMONIC_HIGH_HEELS:
				default:
					text = "skin";
					break;
			}
			return text;
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players neck
	 * @since December 19, 2016
	 * @author Stadler76
	 */
	public class Neck extends BaseBodyPart
	{
		public static const NORMAL:int     =   0; // normal human neck. neckLen = 2 inches
		public static const DRACONIC:int   =   1; // (western) dragon neck. neckLen = 2-30 inches
		public static const COCKATRICE:int =   2;

		public var type:Number  = NORMAL;
		public var len:Number   = 2;
		public var pos:Boolean  = false;
		public var color:String = "no";

		private var _nlMax:Array = [];
		public function get nlMax():Array { return _nlMax; }

		public function Neck()
		{
			_nlMax[NORMAL]   =  2;
			_nlMax[DRACONIC] = 30;
		}

		public function restore():void
		{
			type  = NORMAL;
			len   = 2;
			pos   = false;
			color = "no";
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))  type  = p.type;
			if (p.hasOwnProperty('len'))   len   = p.len;
			if (p.hasOwnProperty('pos'))   pos   = p.pos;
			if (p.hasOwnProperty('color')) color = p.color;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}

		public function modify(diff:Number, newType:Number = -1):void
		{
			if (newType !== -1) type = newType;

			if (_nlMax[type] === undefined) { // Restore length and pos, if the type is not associated with a certain max length
				pos = false;
				len = 2;
				return;
			}

			len += diff;
			if (len < 2)  len = 2;
			if (len > _nlMax[type]) len = _nlMax[type];
		}

		public function isFullyGrown():Boolean
		{
			return len >= _nlMax[type];
		}

		override public function canDye():Boolean
		{
			return type === COCKATRICE;
		}

		override public function hasDyeColor(_color:String):Boolean
		{
			return color === _color;
		}

		override public function applyDye(_color:String):void
		{
			color = _color;
		}

		public function toObject():Object
		{
			return {
				type:  type,
				len:   len,
				pos:   pos,
				color: color
			};
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the piercing constants
	 * @since November 10, 2017
	 * @author Stadler76
	 */
	public class Piercing
	{
		public static const NONE:int   =   0;
		public static const STUD:int   =   1;
		public static const RING:int   =   2;
		public static const LADDER:int =   3;
		public static const HOOP:int   =   4;
		public static const CHAIN:int  =   5;
	}
}


code:
How to work with the BodyParts-classes
======================================

Preface
-------

The `BodyParts` classes are container classes to keep multiple related propertys of complex body parts in a single class, so coders have a slightly easier job to handle them.

For example many TFs reset the players skin by setting all of their values to their default value one by one. Or it could happen, that you forget to update the skinAdj when (re)setting the players Skin. This is now possible with one method call, like
```as3
// Restore everything to its default
player.rearBody.restore(false);

// Restore everything except the skintone to its default
player.skin.restore();
```

General methods
---------------

### restore()
restores the bodypart to the default (human or nonexistant)

Example:
```as3
player.neck.restore();
```

### setProps(p:Object)
sets multiple props at once. Skipped propertys are left untouched.

Example:
```as3
player.skin.setProps({
	type: SKIN_TYPE_LIZARD_SCALES,
	adj: "",
	desc: "scales"
});
```
or put that into a single line:

```as3
player.skin.setProps({type: SKIN_TYPE_DRAGON_SCALES, adj: "tough", desc: "shield-shaped dragon scales"});
```

Another example for BodyParts with a `skin` property:
```as3
player.rearBody.setProps({
    type: REAR_BODY_DRACONIC_MANE,
    skin: {
        type: SKIN_TYPE_DRAGON_SCALES,
        tone: player.skin.tone,
        desc: "shield-shaped dragon scales",
        adj: "test!"
    }
});
```

### setAllProps(p:Object)
same as above, but skipped propertys are being reset to their default values

### canDye() / canOil()
Returns `true` if you can apply hair dye, respectively skin oil to that bodypart

### hasDyeColor(_color:String) / hasOilColor(_color:String)
Returns `true` if the bodypart already has the color to be applied

### applyDye(_color:String) / applyOil(_color:String)
Applies the color to the bodypart

### toObject()
Returns an object with all the public propertys that should be stored in a save file.

Used in:
- `Neck`
- `RearBody`
- `Skin`
- `UnderBody`

BodyParts
---------

### Skin
#### Property table
| Property   | Old (aliased)
Property | Access example          | Description / Examples                                                                                |
|------------|---------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------------|
| `type`     | `skinType`                | `player.skin.type`      | **The type**
`player.skin.type = SKIN_TYPE_FUR;`                                                                      |
| `tone`     | `skinTone`                | `player.skin.tone`      | **The color**
`player.skin.tone = "green-yellow";`
 → "You have **green-yellow** skin."                            |
| `desc`     | `skinDesc`                | `player.skin.desc`      | **The description**
`player.skin.desc = "dragon scales";`
 → "You have red **dragon scales**."                     |
| `adj`      | `skinAdj`                 | `player.skin.adj`       | **The adjective** (changed with body lotions)
`player.skin.adj = "smooth";`
 → "You have **smooth**, green scales" |
| `furColor` | `furColor`                | `player.skin.furColor`  | **The fur color**
`player.skin.furColor = "brown";`                                                                   |

#### Additional mehods
##### public function description(noAdj:Boolean = false, noTone:Boolean = false):String
Always returns the players skin description, even if its hidden behind fur. Setting `noAdj` to `true` skips the adjective and setting `noTone` to `true` additionally skips the skin tone.

###### Usage table:
| Example call                          |   Parser tag   | Example result                       |
|---------------------------------------|----------------|--------------------------------------|
| `player.skin.description()`           | `[skin]`       | "You have **smooth, green scales**." |
| `player.skin.description(true)`       | `[skin.noadj]` | "You have **green scales**."         |
| `player.skin.description(true, true)` | `――――――――――――` | "You have **scales**."               |

`Character.skin()` has been refactored and moved to `Creature.skinDescript()` and is now an alias of `BodyParts.Skin.description()`

In other words (for example):
```as3
outputText(player.skinDescript(true, true));
// is the same as calling
outputText(player.skin.description(true, true));
```

##### public function skinFurScales():String
Moved from and aliased to `Creature.skinFurScales()`

Parser tag: `[skinfurscales]` (case insensitive)

###### Example:
```as3
outputText("You have " + player.skin.skinFurScales() + "!"); // and
outputText("You have [skinFurScales]!");
// both return: "You have soft, orange fur!"
```
Assuming that:
- `type` is set to `SKIN_TYPE_FUR`
- `adj` is set to "soft"
- `furColor` is set to "orange"
- `desc` is set to "fur"

##### public function hasFur():Boolean
Moved from and alias of `Creature.hasFur()`

Returns true if the player has fur (aka `player.skin.type == SKIN_TYPE_FUR`). Nuff said.

##### public function hasWool():Boolean
Alias of `Creature.hasWool()`

Returns true if the player has wool (aka `player.skin.type == SKIN_TYPE_WOOL`).

##### public function hasFeathers():Boolean
Alias of `Creature.hasFeathers()`

Returns true if the player has feathers (aka `player.skin.type == SKIN_TYPE_FEATHERED`).

##### public function isFurry():Boolean
Alias of `Creature.isFurry()`

Returns true if the player has fur or wool.

##### public function isFluffy():Boolean
Alias of `Creature.isFluffy()`

Returns true if the player has fur, wool or feathers.

#### Note
I've added the optional param `keepTone` to the methods `restore()` and `setAllProps()` which defaults to true.
Method headers:
```as3
public function restore(keepTone:Boolean = true):Skin {}
public function setAllProps(p:Object, keepTone:Boolean = true):Skin {}
```
As the params name suggests, it leaves the skintone untouched, if its been set to true which is the default.

Example:
```as3
player.skin.restore();      // Restores all values except the skin tone
player.skin.restore(false); // Restores all values including the skin tone
```

### UnderBody
#### Property table
| Property | Access example          | Description / Examples                                                 |
|----------|-------------------------|------------------------------------------------------------------------|
| `type`   | `player.underBody.type` | **The type**
`player.underBody.type = UNDER_BODY_TYPE_REPTILE;`     |
| `skin`   | `player.underBody.skin` | **The skin on the underbody**
`player.underBody.skin = new Skin();` |

#### Additional methods
##### skinDescription
Alias of `skin.description()` (Same as above, but for the skin on the underbody)

##### skinFurScales
Alias of `skin.skinFurScales()` (Same as above, but for the skin on the underbody)

Parser tag: `[underbody.skinfurscales]` (case insensitive)

#### Examples
##### From lizard scales TF:
```as3
player.skin.setProps({
	type: SKIN_TYPE_LIZARD_SCALES,
	adj: "",
	desc: "scales"
});
player.underBody.type = UNDER_BODY_TYPE_REPTILE;
player.copySkinToUnderBody({    // copy the main skin props to the underBody skin ...
	desc: "ventral scales"  // ... and only override the desc
});
```

You can always set the propertys to be overridden manually after copying the skin-propertys:
```as3
player.skin.setProps({
	type: SKIN_TYPE_LIZARD_SCALES,
	adj: "",
	desc: "scales"
});
player.underBody.type = UNDER_BODY_TYPE_REPTILE;
player.copySkinToUnderBody();                    // copy the main skin props to the underBody skin ...
player.underBody.skin.desc = "ventral scales";   // ... and only override the desc
```

##### Another example:
Let's say, we intend to have some kind of turtle girl TF in CoC, the TF code *could* go this way (Not suggesting anything here, its just an example!):

```as3
// First step: The player grows lizard scales on his/her skin and/or underbody
if ((!player.hasLizardScales() || [UNDER_BODY_TYPE_REPTILE, UNDER_BODY_TYPE_TURTLE].indexOf(player.underBody.type) == -1) && player.lowerBody == LOWER_BODY_TYPE_TURTLE /* && ... */) {
	outputText("... You grow " + player.skin.tone + " scales on your skin!");
	player.skin.setProps({
		type: SKIN_TYPE_LIZARD_SCALES,
		adj: "",
		desc: "scales"
	});
	player.underBody.type = UNDER_BODY_TYPE_REPTILE;
	player.copySkinToUnderBody({    // copy the main skin props to the underBody skin ...
		desc: "ventral scales"  // ... and only override the desc
	});
	changes++;
}

// Second step: The player grows the signature turtle shell on his/her belly
if (player.hasLizardScales() && player.underBody.type == UNDER_BODY_TYPE_REPTILE && player.lowerBody == LOWER_BODY_TYPE_TURTLE /* && ... */) {
	outputText("... The [underBody.skinFurScales] on your belly start to harden to become a sturdy frontal shell to protect your body as a natural armor");
	player.underBody.type = UNDER_BODY_TYPE_TURTLE; // We're done, yay!
	changes++;
}
```

### Wings
#### Property table
| Property | Access example       | Description / Examples                                           |
|----------|----------------------|------------------------------------------------------------------|
| `type`   | `player.wings.type`  | **The type**
`player.wings.type = WING_TYPE_FEATHERED_LARGE;` |
| `color`  | `player.wings.color` | **The color**
`player.wings.color = "green";`                 |

### Neck
#### Property table
| Property | Access example      | Description / Examples                                                                         |
|----------|---------------------|------------------------------------------------------------------------------------------------|
| `type`   | `player.neck.type`  | **The type**
`player.neck.type = NECK_TYPE_DRACONIC;`                                       |
| `len`    | `player.neck.len`   | **The length**
`player.neck.len = 30;`                                                      |
| `pos`    | `player.neck.pos`   | **The position related to the head, true if its behind the face**
`player.neck.pos = true;` |
| `color`  | `player.neck.color` | **The color (e. g. the feathers of a cockatrice neck**
`player.neck.color = "green";`       |

#### Additional methods
##### modify(diff:Number, newType:Number = -1)
Modify the length of the neck by `diff`. Optinally set the type to `newType` before modifying the length

##### isFullyGrown()
Checks, if the neck has reached its max length for the type

##### Notes
Currently only the dragon neck (`NECK_TYPE_DRACONIC`) uses the methods `modify` and `isFullyGrown` and the propertys `len` and `pos`. Ideas for more races with inhuman necks would be appreciated.

### RearBody
#### Property table
| Property | Access example          | Description / Examples                                                                      |
|----------|-------------------------|---------------------------------------------------------------------------------------------|
| `type`   | `player.rearBody.type`  | **The type**
`player.rearBody.type = REAR_BODY_DRACONIC_MANE;`                           |
| `color`  | `player.rearBody.color` | **The color (e. g. the hair of a hair draconic mane**
`player.rearBody.color = "green";` |

#### Additional methods
None so far

Changed or new related methods
------------------------------

Syntax: ClassName.methodName

##### Creature.copySkinToUnderBody(p:Object = null)
This is mainly a wrapper around
```as3
player.underBody.skin.setProps(player.skin);
```
The param `p:Object = null` can optionally be used to override certain skin propertys after copying them (See in the examples for UnderBody)

### Player.setFurColor
Set the new furColor or furColors randomly and, if wanted: set the new underBody as well.

#### Param `colorArray:Array`
The method still accepts a list of strings to randomly choose from as the new furColor for BC, but in addition to that it now accepts a mixed list of strings and arrays with two strings.

##### Example
```as3
player.setFurColor([
	"orange",
	"brown",
	"black",
	"gray",
	"white",
	["orange", "white"],
	["brown", "white"],
	["black", "white"],
	["gray", "white"],
]);
```
If the randomizer chooses one of the first five options, only the main furColor aka `player.furColor` is being set (old behaviour still works),
but for the last four options, the array specifies the main furColor and the furColor on the underBody.

So, if the choice is `["orange", "white"]` for example, it would be the same as:
```as3
player.furColor = "orange";
player.underBody.furColor = "white";
```

#### Param `underBodyProps:Object = null`
In addition to setting the furColor(s) you may want to override a few or all underBody-props, too. You can do that here. (See the example below)

#### Param `doCopySkin:Boolean = false`
Set this to true, if you want to copy the skin-props to the underBody before overriding the underBody.skin. (See the example below)

#### Param `restoreUnderBody:Boolean = true`
If set to true (the default), the underBody is restored before setting the other values. In most, if not all cases, its not needed to set this to false and its always a good idea to clean up the underBody first (or in case the creature has no inhuman underBody)

##### Example
```as3
player.setFurColor(catFurColors, {type: UNDER_BODY_TYPE_FURRY}, true);
```
See the example above for potential `catFurColors`

### Player.setSkinTone
Same as `Player.setFurColor` but for the skinTone(s). Currently not used.

### PlayerHelper.hasDifferentUnderBody
Returns true, if the main skin and the underBody-skin differs somehow and false otherwise.
The furColor is only compared, if both the main skin and the underBody skin are furry of course.
If the player has no inhuman underBody it returns false. And certain underBody-types, like naga underBody are handled differently, hence it returns false with these, too.

### Character.nagaLowerBodyColor2
Like I stated above: Naga underBody is handled differently and since it has two colors at least (one for the underside and one for the rest), this method returns the secondary (underside) color depending on the primary naga lower body color (`player.underBody.skin.tone` here).
Actually, this is a wrapper around `Appearance.nagaLowerBodyColor2`

### Utils.convertMixedToStringArray(list:Array):Array
In order to get the mixed color lists (string vs. arrays of strings, see `Player.setFurColor` above) to play nicely with `Utils.InCollection` the array needs to be altered to contain strings only.

##### Example
```as3
var colorList:Array = [
	"blue",
	"green",
	["black", "white", "gray"],
	["red", "orange"],
	"blue"
];

convertMixedToStringArray(colorList);
// returns ["blue", "green", "black, white and gray", "red and orange", "blue"]
```


code:
package classes.BodyParts
{
	import classes.Creature;

	/**
	 * Container class for the players rear body
	 * @since December 20, 2016
	 * @author Stadler76
	 */
	public class RearBody extends BaseBodyPart
	{
		public static const NONE:int            =   0;
		public static const DRACONIC_MANE:int   =   1;
		public static const DRACONIC_SPIKES:int =   2;
		public static const SHARK_FIN:int       =   3;
		public static const BARK:int			=   4;

		public var type:Number  = NONE;
		public var color:String = "no";

		public function restore():void
		{
			type  = NONE;
			color = "no";
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))  type  = p.type;
			if (p.hasOwnProperty('color')) color = p.color;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}

		override public function canDye():Boolean
		{
			return type === DRACONIC_MANE;
		}

		override public function hasDyeColor(_color:String):Boolean
		{
			return color === _color;
		}

		override public function applyDye(_color:String):void
		{
			color = _color;
		}

		public function toObject():Object
		{
			return {
				type:  type,
				color: color
			};
		}
	}
}


code:
package classes.BodyParts
{
	import classes.Appearance;

	/**
	 * Container class for the players skin
	 * @since December 27, 2016
	 * @author Stadler76
	 */
	public class Skin
	{
		public static const PLAIN:int         =   0;
		public static const FUR:int           =   1;
		public static const LIZARD_SCALES:int =   2;
		public static const GOO:int           =   3;
		public static const UNDEFINED:int     =   4; // DEPRECATED, silently discarded upon loading a saved game
		public static const DRAGON_SCALES:int =   5;
		public static const FISH_SCALES:int   =   6; // NYI, for future use
		public static const WOOL:int          =   7;
		public static const FEATHERED:int     =   8;
		public static const BARK:int          =   9;
		public static const STALK:int		  =  10;
		public static const WOODEN:int		  =  11;

		public var type:Number = PLAIN;
		public var tone:String = "albino";
		public var desc:String = "skin";
		public var adj:String = "";
		public var furColor:String = "no";

		public function setType(value:Number):void
		{
			desc = Appearance.DEFAULT_SKIN_DESCS[value];
			type = value;
		}

		public function skinFurScales():String
		{
			var skinzilla:String = "";
			//Adjectives first!
			if (adj !== "")
				skinzilla += adj + ", ";

			//Fur handled a little differently since it uses haircolor
			skinzilla += isFluffy() ? furColor : tone;

			return skinzilla + " " + desc;
		}

		public function description(noAdj:Boolean = false, noTone:Boolean = false):String
		{
			var skinzilla:String = "";

			//Adjectives first!
			if (!noAdj && adj !== "" && !noTone && tone !== "rough gray")
				skinzilla += adj + ", ";
			if (!noTone)
				skinzilla += tone + " ";

			//Fur handled a little differently since it uses haircolor
			skinzilla += isFluffy() ? "skin" : desc;

			return skinzilla;
		}

		public function hasFur():Boolean
		{
			return type === FUR;
		}

		public function hasWool():Boolean
		{
			return type === WOOL;
		}

		public function hasFeathers():Boolean
		{
			return  type === FEATHERED;
		}

		public function isFurry():Boolean
		{
			return [FUR, WOOL].indexOf(type) !== -1;
		}

		public function isFluffy():Boolean
		{
			return [FUR, WOOL, FEATHERED].indexOf(type) !== -1;
		}

		public function restore(keepTone:Boolean = true):void
		{
			type = PLAIN;
			if (!keepTone) tone = "albino";
			desc = "skin";
			adj  = "";
			furColor = "no";
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
			if (p.hasOwnProperty('tone')) tone = p.tone;
			if (p.hasOwnProperty('desc')) desc = p.desc;
			if (p.hasOwnProperty('adj'))  adj  = p.adj;
			if (p.hasOwnProperty('furColor')) furColor = p.furColor;
		}

		public function setAllProps(p:Object, keepTone:Boolean = true):void
		{
			restore(keepTone);
			setProps(p);
		}

		public function toObject():Object
		{
			return {
				type:     type,
				tone:     tone,
				desc:     desc,
				adj:      adj,
				furColor: furColor
			};
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players tail
	 * @since November 05, 2017
	 * @author Stadler76
	 */
	public class Tail
	{
		public static const NONE:int           =   0;
		public static const HORSE:int          =   1;
		public static const DOG:int            =   2;
		public static const DEMONIC:int        =   3;
		public static const COW:int            =   4;
		public static const SPIDER_ABDOMEN:int =   5;
		public static const BEE_ABDOMEN:int    =   6;
		public static const SHARK:int          =   7;
		public static const CAT:int            =   8;
		public static const LIZARD:int         =   9;
		public static const RABBIT:int         =  10;
		public static const HARPY:int          =  11;
		public static const KANGAROO:int       =  12;
		public static const FOX:int            =  13;
		public static const DRACONIC:int       =  14;
		public static const RACCOON:int        =  15;
		public static const MOUSE:int          =  16;
		public static const FERRET:int         =  17;
		public static const BEHEMOTH:int       =  18;
		public static const PIG:int            =  19;
		public static const SCORPION:int       =  20;
		public static const GOAT:int           =  21;
		public static const RHINO:int          =  22;
		public static const ECHIDNA:int        =  23;
		public static const DEER:int           =  24;
		public static const SALAMANDER:int     =  25;
		public static const WOLF:int           =  26;
		public static const SHEEP:int          =  27;
		public static const IMP:int            =  28;
		public static const COCKATRICE:int     =  29;
		public static const RED_PANDA:int      =  30;

		public var type:Number     = NONE;
		/** Tail venom is a 0-100 slider used for tail attacks. Recharges per hour. */
		public var venom:Number    = 0;
		/** Tail recharge determines how fast venom/webs comes back per hour. */
		public var recharge:Number = 5;

		public function restore():void
		{
			type     = NONE;
			venom    = 0;
			recharge = 5;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))     type     = p.type;
			if (p.hasOwnProperty('venom'))    venom    = p.venom;
			if (p.hasOwnProperty('recharge')) recharge = p.recharge;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players tongue
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class Tongue
	{
		public static const HUMAN:int    =   0;
		public static const SNAKE:int    =   1;
		public static const DEMONIC:int  =   2;
		public static const DRACONIC:int =   3;
		public static const ECHIDNA:int  =   4;
		public static const LIZARD:int   =   5;
		public static const CAT:int      =   6;

		public var type:Number = HUMAN;

		public function restore():void
		{
			type = HUMAN;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players udder
	 * @since January 19, 2018
	 * @author NoahTheGoodra
	 */
    public class Udder
	{
		/** Udder hasUdder a bool value that says if the player has an undder */
		public var hasUdder:Boolean = false;
		/** Udder fullness is a 0-100 slider used for how full the udder is. Recharges per hour. */
		public var fullness:Number = 0;
		/** Udder refill determines how fast milk comes back per hour. */
		public var refill:Number = 5;

		public function restore():void
		{
			hasUdder = false;
			fullness = 0;
			refill = 5;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('hasUdder')) hasUdder = p.hasUdder;
			if (p.hasOwnProperty('fullness')) fullness = p.fullness;
			if (p.hasOwnProperty('refill'))   refill   = p.refill;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}

		public function toObject():Object
		{
			return {
				hasUdder: hasUdder,
				fullness: fullness,
				refill:   refill
			};
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players underbody
	 * @since December 31, 2016
	 * @author Stadler76
	 */
	public class UnderBody
	{
		public static const NONE:int       =   0;
		public static const REPTILE:int    =   1;
		public static const DRAGON:int     =   2; // Deprecated. Changed to 1 (UnderBody.REPTILE) upon loading a savegame
		public static const FURRY:int      =   3;
		public static const NAGA:int       =   4;
		public static const WOOL:int       =   5; // Deprecated. Changed to 3 (UnderBody.FURRY) upon loading a savegame
		public static const COCKATRICE:int =   6;

		public var type:Number = NONE;
		public var skin:Skin = new Skin();

		public function skinDescription(...args):String { return skin.description.apply(null, args); }
		public function skinFurScales(...args):String { return skin.skinFurScales.apply(null, args); }

		public function restore(keepTone:Boolean = true):void
		{
			type  = NONE;
			skin.restore(keepTone);
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type')) type = p.type;
			if (p.hasOwnProperty('skin')) skin.setProps(p.skin);
		}

		public function setAllProps(p:Object, keepTone:Boolean = true):void
		{
			restore(keepTone);
			setProps(p);
		}

		public function toObject():Object
		{
			return {
				type: type,
				skin: skin.toObject()
			};
		}
	}
}


code:
package classes.BodyParts
{
	/**
	 * Container class for the players wings
	 * @since May 01, 2017
	 * @author Stadler76
	 */
	public class Wings extends BaseBodyPart
	{
		public static const NONE:int            =   0;
		public static const BEE_LIKE_SMALL:int  =   1;
		public static const BEE_LIKE_LARGE:int  =   2;
		public static const HARPY:int           =   4;
		public static const IMP:int             =   5;
		public static const BAT_LIKE_TINY:int   =   6;
		public static const BAT_LIKE_LARGE:int  =   7;
		public static const SHARK_FIN:int       =   8; // Deprecated, moved to the rearBody slot.
		public static const FEATHERED_LARGE:int =   9;
		public static const DRACONIC_SMALL:int  =  10;
		public static const DRACONIC_LARGE:int  =  11;
		public static const GIANT_DRAGONFLY:int =  12;
		public static const IMP_LARGE:int       =  13;
		public static const FAERIE_SMALL:int    =  14; // currently for monsters only
		public static const FAERIE_LARGE:int    =  15; // currently for monsters only
		public static const WOODEN:int			=  16;

		public var type:Number  = NONE;
		public var color:String = "no";
		public var color2:String = "no";

		/**
		 * Returns a string that describes, what the actual color number (=id) is for.
		 * e. g.: Dragon Wings main color => "membranes" and secondary color => "bones"
		 * @param   id  The 'number' of the chosen color (main = color, secondary = color2)
		 * @return  The resulting description string
		 */
		override public function getColorDesc(id:int):String
		{
			switch (type) {
				case DRACONIC_SMALL:
				case DRACONIC_LARGE:
					switch (id) {
						case COLOR_ID_MAIN:
							return "membranes";

						case COLOR_ID_2ND:
							return "bones";

						default:
							return "";
					}

				default:
					return "";
			}
		}

		public function restore():void
		{
			type  = NONE;
			color = "no";
			color2 = "no";
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('type'))  type  = p.type;
			if (p.hasOwnProperty('color')) color = p.color;
			if (p.hasOwnProperty('color2')) color2 = p.color2;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}

		override public function canDye():Boolean
		{
			return [HARPY, FEATHERED_LARGE].indexOf(type) !== -1;
		}

		override public function hasDyeColor(_color:String):Boolean
		{
			return color === _color;
		}

		override public function applyDye(_color:String):void
		{
			color = _color;
		}

		override public function canOil():Boolean
		{
			return [DRACONIC_SMALL, DRACONIC_LARGE].indexOf(type) !== -1;
		}

		override public function hasOilColor(_color:String):Boolean
		{
			return color === _color;
		}

		override public function applyOil(_color:String):void
		{
			color = _color;
		}

		override public function canOil2():Boolean
		{
			return [DRACONIC_SMALL, DRACONIC_LARGE].indexOf(type) !== -1;
		}

		override public function hasOil2Color(_color2:String):Boolean
		{
			return color2 === _color2;
		}

		override public function applyOil2(_color2:String):void
		{
			color2 = _color2;
		}
	}
}


code:
package classes {
public class BonusDerivedStats {
    public function BonusDerivedStats() {
    }

    public var statArray:Object = {};

    public static const dodge:String = "Dodge Chance";
    public static const spellMod:String = "Spell Mod";
    public static const critC:String = "Critical Chance";
    public static const critD:String = "Critical Damage";
    public static const maxHealth:String = "Max Health";
    public static const spellCost:String = "Spell Cost";
    public static const accuracy:String = "Accuracy";
    public static const physDmg:String = "Physical Damage";
    public static const healthRegenPercent:String = "Health Regen(%)";
    public static const healthRegenFlat:String = "Health Regen(Flat)";
    public static const minLust:String = "Minimum Lust";
    public static const lustRes:String = "Lust Resistance";
    public static const seduction:String = "Tease Chance";
    public static const sexiness:String = "Tease Damage";
    public static const attackDamage:String = "Attack Damage";
    public static const globalMod:String = "Global Damage";
    public static const weaponDamage:String = "Weapon Damage";
    public static const fatigueMax:String = "Max Fatigue";
	public static const damageMulti:String = "Damage Multiplier";

    public static var goodNegatives:Array = [spellCost,minLust];
    public static var percentageAdditions:Array = [dodge,spellMod,critC,critD,spellCost,accuracy,physDmg,healthRegenPercent,lustRes,attackDamage,globalMod,damageMulti];
    public function boostStat(stat:String,amount:*,mult:Boolean = false, buffSource:String = ""):void{
        statArray[stat] = {
            value: amount,
            multiply: mult,
            key: buffSource
        };
    }
}
}


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;
	import classes.lists.BreastCup;

	public class BreastRow
	{
		public var breasts:Number = 2;
		public var nipplesPerBreast:Number = 1;
		public var breastRating:Number = BreastCup.FLAT;
		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, "BreastRow.validate", [
					"breasts", "nipplesPerBreast", "breastRating", "lactationMultiplier",
					"milkFullness", "fullness"
			]);
			return error;
		}

		public function restore():void
		{
			breasts = 2;
			nipplesPerBreast = 1;
			breastRating = BreastCup.FLAT;
			lactationMultiplier = 0;
			milkFullness = 0;
			fullness = 0;
			fuckable = false;
			nippleCocks = false;
		}

		public function setProps(p:Object):void
		{
			if (p.hasOwnProperty('breasts'))             breasts             = p.breasts;
			if (p.hasOwnProperty('nipplesPerBreast'))    nipplesPerBreast    = p.nipplesPerBreast;
			if (p.hasOwnProperty('breastRating'))        breastRating        = p.breastRating;
			if (p.hasOwnProperty('lactationMultiplier')) lactationMultiplier = p.lactationMultiplier;
			if (p.hasOwnProperty('milkFullness'))        milkFullness        = p.milkFullness;
			if (p.hasOwnProperty('fullness'))            fullness            = p.fullness;
			if (p.hasOwnProperty('fuckable'))            fuckable            = p.fuckable;
			if (p.hasOwnProperty('nippleCocks'))         nippleCocks         = p.nippleCocks;
		}

		public function setAllProps(p:Object):void
		{
			restore();
			setProps(p);
		}
	}
}


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

	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) CoC_Settings.error("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";
					break;
				default:
			}
			return descript + "breasts";
		}

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

		public function set cupSize(value:int):void {
			if (value < BreastCup.FLAT) value = BreastCup.FLAT;
			if (value > BreastCup.ZZZ_LARGE) value = BreastCup.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 BreastCup.FLAT:		return "non-existent";
				case BreastCup.A:			return "small";
				case BreastCup.B:
				case BreastCup.C:			return "palmable";
				case BreastCup.D:
				case BreastCup.DD:
				case BreastCup.DD_BIG:		return "sizeable";
				case BreastCup.E:
				case BreastCup.E_BIG:
				case BreastCup.EE:
				case BreastCup.EE_BIG:
				case BreastCup.F:
				case BreastCup.F_BIG:
				case BreastCup.FF:
				case BreastCup.FF_BIG:		return "huge";
				case BreastCup.G:
				case BreastCup.G_BIG:
				case BreastCup.GG:
				case BreastCup.GG_BIG:
				case BreastCup.H:
				case BreastCup.H_BIG:
				case BreastCup.HH:
				case BreastCup.HH_BIG:
				case BreastCup.I:
				case BreastCup.I_BIG:
				case BreastCup.II:
				case BreastCup.II_BIG:		return "gigantic";
				case BreastCup.J:
				case BreastCup.J_BIG:
				case BreastCup.JJ:
				case BreastCup.JJ_BIG:
				case BreastCup.K:
				case BreastCup.K_BIG:
				case BreastCup.KK:
				case BreastCup.KK_BIG:
				case BreastCup.L:
				case BreastCup.L_BIG:
				case BreastCup.LL:
				case BreastCup.LL_BIG:
				case BreastCup.M:
				case BreastCup.M_BIG:
				case BreastCup.MM:
				case BreastCup.MM_BIG:
				case BreastCup.MMM:
				case BreastCup.MMM_LARGE:	return "mammoth";
				default:
			}
			return("titanic");
		}

		public function canTitFuck():Boolean { return _cupSize >= BreastCup.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 === BreastCup.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 !== BreastCup.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;
		}
	}
}