code:
package classes.GlobalFlags
{
	import classes.CoC;

	public var kGAMECLASS:CoC;
}

license: unknown


code:
package classes
{
	/**
	 * ...
	 * @author Yoffy
	 */
	public class Image
	{
		private var _id:String;
		private var _url:String
		private var _width:int;
		private var _height:int;

		public function Image(id:String, url:String, w:int, h:int)
		{
			_id = id;
			_url = url;
			_width = w;
			_height = h;
		}

		public function get id():String
		{
			return _id;
		}

		public function get url():String
		{
			return _url;
		}

		public function get width():int
		{
			return _width;
		}

		public function get height():int
		{
			return _height;
		}

	}

}


code:
package classes
{
	import classes.Image;
	import classes.GlobalFlags.kFLAGS;
	import classes.GlobalFlags.kGAMECLASS;

	import coc.view.MainView;
    import com.bit101.components.TextFieldVScroll;
	import flash.display.Loader;
	import flash.display.Stage;
	import flash.display.MovieClip;
	import flash.errors.IOError;
	import flash.net.*;
	import flash.events.*;

	import flash.system.Security;
	import flash.text.TextField;
	import flash.text.TextFormat;

	import mx.logging.ILogger;
	import classes.internals.LoggerFactory;

	/**
	 * ...
	 * @author Yoffy, Fake-Name
	 */
	public final class ImageManager
	{
		private static const LOGGER:ILogger = LoggerFactory.getLogger(ImageManager);
		//Hashmap of all images
		private static var _imageTable:Object = new Object();

		// map of all the potential image paths from the xml file
		private static var _allImagePaths:Object = new Object();
		// Used to map fully-qualified paths to relative paths so we can lookup the information used to load them.
		private static var _fqPathMap:Object = new Object();

		private var mStage:Stage;

		//Maximum image box size
		private const MAXSIZE:int = 400;

		public var xmlLoadError:Boolean = false;
		private var logErrors:Boolean = false;

		//The magic embedding sauce. Skips around sandbox issue by embedding the
		//xml into the swf. Makes it possible to load images even from a browser.

		[Embed(source="../../img/images.xml",mimeType="application/octet-stream")]

		private static const XML_IMAGES:Class;
		private var _imgListXML:XML;
		private var _mainView:MainView;

		public function ImageManager(stage:Stage, mainView:MainView)
		{
			_mainView = mainView;
			mStage = stage;
			_imgListXML = new XML(new XML_IMAGES);
			if (Security.sandboxType != Security.REMOTE && !CONFIG::AIR)
			{
				//trace("Creating Image File hashmap");
				loadImageList();
			}
		}

		public function loadImageList():void
		{

			for (var i:int = 0; i < _imgListXML.ImageList.ImageSet.length(); i++)
			{
				for (var j:int = 0; j <  _imgListXML.ImageList.ImageSet[i].ImageFile.length(); j++)
				{
					for (var k:int = 0; k < _imgListXML.ExtensionList.ExtensionType.length(); k++)
					{
						// Programmatic extension concatenation! Woot.
						_allImagePaths[_imgListXML.ImageList.ImageSet[i].ImageFile[j]+"."+_imgListXML.ExtensionList.ExtensionType[k]] = _imgListXML.ImageList.ImageSet[i].@id;
					}
				}
			}
			for (var imgPath:String in _allImagePaths)
			{
				// trace(_allImagePaths[imgPath], " : ", imgPath)
				this.loadImageAtPath(imgPath);
			}

			//trace("Loading imagelist", imgLoader, req, _imgListXML)
		}

		private function loadImageAtPath(imPath:String):void
		{
			var imgLoader:Loader = new Loader();

			var f:Function = function(key:String):Function
			{

				return function(e:Event):void
				{
					fileLoaded(e, key);
				}
			}

			imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, f(imPath));
			imgLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, fileNotFound);
			var req:URLRequest = new URLRequest(imPath);
			imgLoader.load(req);
		}

		private function fileLoaded(e:Event, imPath:String):void
		{

			if (_allImagePaths.hasOwnProperty(imPath))
			{
				var extImage:Image;
				// split the image name out from the image path.

				// trace("ImageFile - ", _allImagePaths[imPath], imPath);
				var imId:String = _allImagePaths[imPath]
				extImage = new Image(imId, imPath, e.target.width, e.target.height);

				// Store the fully-qualified<->image mapping for later use.
				_fqPathMap[e.target.url] = extImage;

				if (_imageTable[extImage.id] == undefined)
				{
					_imageTable[extImage.id] = new Array(extImage);
				}
				else
				{
					// trace("Pushing additional image onto array", extImage.id, extImage)
					_imageTable[extImage.id].push(extImage);
				}

				// If there is a underscore in the image path, the image is intended to be one of a set for the imageID
				// Therefore, we split the index integer off, increment it by one, and try to load that path
				var underscorePt:int = imPath.lastIndexOf("_");
				if (underscorePt != -1)
				{
					var decimalPt:int = imPath.lastIndexOf(".");
					var prefix:String = imPath.slice(0, underscorePt+1);
					var num:String = imPath.slice(underscorePt+1, decimalPt);
					num = String(int(num)+1);

					// Try all possible extensions.
					for (var k:int = 0; k < _imgListXML.ExtensionList.ExtensionType.length(); k++)
					{
						// Programmatic extension concatenation! Woot.
						var newPath:String = prefix+num+"."+_imgListXML.ExtensionList.ExtensionType[k];
						if (logErrors) LOGGER.debug("Trying to load sequential image at URL =", newPath, "Previous base URL = ", imPath);
						_allImagePaths[newPath] = imId;
						loadImageAtPath(newPath);

					}

				}

			}
			else
			{
				if (logErrors) LOGGER.error("Error in image loading. Tried to load image that was not tried to load? Wat.")
			}

			//trace("Loaded file", e)
		}

		private function fileNotFound(e:IOErrorEvent):void
		{
			//trace("File not Found: " + e);
		}

		public function getLoadedImageCount():int
		{
			var cnt:int=0;
			for (var s:String in _imageTable) cnt++;
			return cnt;
		}

		// Find the image data for the given image URL and return the displayed height
		public function getImageHeight(imageURL:String):int
		{
			// Slice off the leading directories and extension to get the image name

			var imageTarget:Image = _fqPathMap[imageURL];

			if (imageTarget == null)
			{
				return 1;
			}
			else
			{
				var ratio:Number = imageTarget.width / imageTarget.height;

				// Image resized vertically
				if (ratio >= 1)
				{
					return Math.ceil(imageTarget.height * (MAXSIZE / imageTarget.width));
				}
				// Image was scaled horizontally, return max height
				else
				{
					return MAXSIZE;
				}
			}
		}

		public function showImage(imageID:String, align:String = "left"):String
		{
			var imageString:String = "";

			if (kGAMECLASS.flags[kFLAGS.IMAGEPACK_ENABLED] <= 0) {
				return "";
			}

			if (logErrors) LOGGER.error("showing imageID - ", imageID);
			var imageIndex:int = 0;
			var image:Image = null;
			if (_imageTable[imageID] != undefined)
			{
				// More than 1 image? Pick one at random.
				if (_imageTable[imageID].length > 0)
				{
					imageIndex = Math.floor( Math.random() * _imageTable[imageID].length );
					if (logErrors) LOGGER.debug("Have multiple image possibilities. Displaying image", imageIndex, "selected randomly.");
					image = _imageTable[imageID][imageIndex];
				}
			}

			if (image != null)
			{
				if (align == "left" || align == "right")
				{
					//Scale images down to fit the box
					var ratio:Number = image.width / image.height;
					var scaler:Number;

					if (ratio >= 1)
					{
						scaler = MAXSIZE / image.width;
						imageString = "";
					}
					else
					{
						scaler = MAXSIZE / image.height;
						imageString = "";
					}
				}
			}
			//trace("Loading image: " + imageID + ", html: " + imageString);
			fixupImage();
			return imageString;
		}

		// Begin our image fixing code
		private function fixupImage():void
		{
			mStage.addEventListener(Event.ADDED, fixupListener);
		}

		// Event listener hooks into the stage to find objects added to the display list at any point in the heirarchy
		private function fixupListener(e:Event):void
		{
			// We're looking for Loader objects -- there /could/ be other types of loaders in future, but right now,
			// the only thing that will create loaders is the mainText field when it parses an  tag
			if (e.target is Loader)
			{
				mStage.removeEventListener(Event.ADDED, fixupListener);
				var loader:Loader = e.target as Loader;

				// Hook the loader to notify us when the image has finished loading
				// this gaurantees that anything we do to the content of mainText will ONLY happen after a scene's calls
				// to outputText has finished
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, doFixup);
			}
		}

		/**
		 * Meat of the image padding fix.
		 * The images XY position is relative to its position inside of the containing TextField. Compare the image.Y + image.height
		 * to the maximal Y position of text in the TextField /once the image has reflowed the text, possibly adding more height to the text.
		 * Handwave the difference in this pixel height as a line count (this could be more accurate by using TextMetrics, but fuck it) and
		 * add this many blank lines to the text.
		 * Critical point; once the new lines have been added to the text, force an update of the scrollbar UI element (its actually a seperate
		 * UI component that "targets" the TextField, and not actually a part of the TextField itself) to account for the new text height.
		 *
		 * Handwavey Bullshit Internals:
		 * TextField.htmlText doesn't continually "parse" content added to it, it's done at the end of a frame when the property has changed.
		 * 		(TextField has two internal properties to check its current displayed content after parsing, and what other code has told it to have there,
		 * 	     the difference is only resolved on EVENT.EXIT_FRAME or EVENT.ENTER_FRAME, I'm not sure which but thats basically the mechanic in play)
		 * TextField never directly updates the UIScrollBar, it's kinda the other way around but not really; the UIScrollBar targets a specific DisplayObject
		 * and targets specific properties thereof. It's probably (internally) adding a listener to EVENT.CHANGE which, I believe, will only be fired when
		 * the textfields internal text property is updated (ie not htmlText but the comparison with it). Anything that changes the actual content layout
		 * of the TextField (and thus the maxScrollV property, which tracks the maximum number of lines displayed via the text field) does not fire the event.
		 *
		 * In summary. ADOBE DURR. This kind of stupid, half-implemented interaction between base UI components is systematic.
		 * @param	e
		 */
		public function doFixup(e:Event):void
		{
			// Remove the Completion event listener
			e.target.removeEventListener(Event.COMPLETE, doFixup);
			var imgRef:Loader = e.target.loader as Loader;
			var mainText:TextField = _mainView.mainText;
			var scrollBar:TextFieldVScroll = _mainView.scrollBar;

			var imgRefTopY:int = imgRef.getBounds(mainText).y; 							// 272
			var imgHeight:int = getImageHeight(imgRef.contentLoaderInfo.url); 			// 400
			var imgRefBottomY:int = imgRefTopY + imgHeight;
			var totalTextHeight:int = mainText.textHeight; 								// 264 -- Total displayed pixel height of text

			if (totalTextHeight > imgRefBottomY)
			{
				// Total displayed text height should be larger than the image
				return;
			}

			// Here comes the bullshit... get ready
			var txFormat:TextFormat = mainText.defaultTextFormat;
			var lineHeight:int = txFormat.size as int;
			lineHeight += 4;
			var padLines:int = Math.ceil((imgRefBottomY - totalTextHeight) / lineHeight);

			// Generate the paddings
			var padding:String = "";
			for (var i:int = 0; i < padLines; i++)
			{
				padding += "\n";
			}
			mainText.htmlText += padding;
			scrollBar.draw();
		}
	}
}


code:
package classes
{
	import classes.display.BindingPane;
	import classes.internals.LoggerFactory;
	import coc.view.MainView;
	import flash.display.Stage;
	import flash.events.KeyboardEvent;
	import flash.text.TextField;
	import mx.logging.ILogger;
	/**
	 * Generic input manager
	 * I feel sick writing some of these control functors; rather than having some form of queryable game state
	 * we're checking for the presence (and sometimes, the label contents) of UI elements to determine what state
	 * the game is currently in.
	 * @author Gedan
	 */
	public class InputManager
	{
		private static const LOGGER:ILogger = LoggerFactory.getLogger(InputManager);
		// Declaring some consts for clarity when using some of the InputManager methods
		public static const PRIMARYKEY:Boolean = true;
		public static const SECONDARYKEY:Boolean = false;
		public static const NORMALCONTROL:Boolean = false;
		public static const CHEATCONTROL:Boolean = true;
		public static const UNBOUNDKEY:int = -1;

		private var _stage:Stage;
		private var _debug:Boolean;

		private var _defaultControlMethods:Object = new Object();
		private var _defaultAvailableControlMethods:int = 0;
		private var _defaultKeysToControlMethods:Object = new Object();

		// Basically, an associative list of Names -> Control Methods
		private var _controlMethods:Object = new Object();
		private var _availableControlMethods:int = 0;

		// A list of cheat control methods that we can throw incoming keycodes against at will
		private var _cheatControlMethods:Array = new Array();
		private var _availableCheatControlMethods:int = 0;

		// The primary lookup method for finding what method an incoming keycode should belong too
		// Sparse array of keyCode -> BoundControlMethod.Name, used to look into _controlMethods
		private var _keysToControlMethods:Object = new Object();

		// Visual shit
		private var _mainView:MainView;
		private var _mainText:TextField;

		// A new UI element that we can embed buttons into to facilitate key rebinding
		private var _bindingPane:BindingPane;

		// A flag to determine if we're listening for keyCodes to execute, or keyCodes to bind a method against
		private var _bindingMode:Boolean;
		private var _bindingFunc:String;
		private var _bindingSlot:Boolean;

		/**
		 * Init the InputManager. Attach the keyboard event listener to the stage and prepare the subobjects for usage.
		 * @param	stage	Reference to core stage on which to add display objects
		 * @param	_mainView
		 * @param	debug	Emit debugging trace statements
		 */
		public function InputManager(stage:Stage,
									 _mainView: MainView,
									 debug:Boolean = true)
		{
			_bindingMode = false;
			_debug = debug;

			_stage = stage;
			this._mainView = _mainView;
			_availableControlMethods = 0;
			_availableCheatControlMethods = 0;

			_stage.addEventListener(KeyboardEvent.KEY_DOWN, this.KeyHandler);

			_mainText = _mainView.mainText as TextField;

			_bindingPane = new BindingPane(this, _mainText.x, _mainText.y, _mainText.width + 16, _mainText.height);
		}

		/**
		 * Mode toggle - keyboard events recieved by the input manager will be used to associated the incoming keycode
		 * with a new bound control method, removing the keycode from *other* bindings and updating data as appropriate.
		 * Displays a message indicating the player should do the needful.
		 * @param	funcName	BoundControlMethod name that they key is going to be associated with. Set by a button
		 * 						callback function generated in BindingPane
		 * @param	isPrimary	Specifies if the incoming bind will replace/set the primary or secondary bind for a control.
		 */
		public function ListenForNewBind(funcName:String, isPrimary:Boolean = true):void
		{
			if (_debug)
			{
				var slot:String = "";

				if (isPrimary)
				{
					slot = "Primary";
				}
				else
				{
					slot = "Secondary";
				}

				LOGGER.debug("Listening for a new " + slot + " bind for " + funcName);
			}

			_bindingMode = true;
			_bindingFunc = funcName;
			_bindingSlot = isPrimary;

			_mainText.htmlText = "<b>Hit the key that you want to bind " + funcName + " to!</b>";

			// hide some buttons that will fuck shit up
			_mainView.hideCurrentBottomButtons();

			HideBindingPane();
		}

		/**
		 * Mode toggle - return to normal keyboard event listening mechanics. Shows the binding display again.
		 */
		public function StopListenForNewBind():void
		{
			_bindingMode = false;
			_mainView.showCurrentBottomButtons();
			DisplayBindingPane();
		}

		/**
		 * Add a new action that can be associated with incoming key codes.
		 * This will mostly be static after first being initialized, this pattern was just easier to capture references
		 * to the required game functions without having to make the InputManager truely global or doing any namespacing
		 * shenanigans.
		 * The closure can be declared with the rest of the game code, in the namespace where the functions are available,
		 * and still work inside this object.
		 * @param	name		Name to associate the BoundControlMethod with
		 * @param	desc		A description of the activity that the BoundControlMethod does. (Unused, but implemented)
		 * @param	func		A function object that defines the BoundControlMethods action
		 * @param	isCheat		Differentiates between a cheat method (not displayed in the UI) and normal controls.
		 */
		public function AddBindableControl(name:String, desc:String, func:Function, isCheat:Boolean = false):void
		{
			if (isCheat)
			{
				_cheatControlMethods.push(new BoundControlMethod(func, name, desc, _availableCheatControlMethods++));
			}
			else
			{
				_controlMethods[name] = new BoundControlMethod(func, name, desc, _availableControlMethods++);
			}
		}

		/**
		 * Set either the primary or secondary binding for a target control method to a given keycode.
		 * @param	keyCode		The keycode to bind the method to.
		 * @param	funcName	The name of the associated BoundControlMethod
		 * @param	isPrimary	Specifies the primary or secondary binding slot
		 */
		public function BindKeyToControl(keyCode:int, funcName:String, isPrimary:Boolean = true):void
		{
			for (var key:String in _controlMethods)
			{
				// Find the method we want to bind the incoming key to
				if (funcName == key)
				{
					// Check if the incoming key is already bound to *something* and if it is, remove the bind.
					this.RemoveExistingKeyBind(keyCode);

					// If we're binding the primary key of the method...
					if (isPrimary)
					{
						// If the primary key of the method is already bound, removing the existing bind
						if (_controlMethods[key].PrimaryKey != InputManager.UNBOUNDKEY)
						{
							delete _keysToControlMethods[_controlMethods[key].PrimaryKey];
						}

						// Add the new bind
						_keysToControlMethods[keyCode] = key;
						_controlMethods[key].PrimaryKey = keyCode;
						return;
					}
					// We're doing the secondary key of the method
					else
					{
						// If the secondary key is already bound, remove the existing bind
						if (_controlMethods[key].SecondaryKey != InputManager.UNBOUNDKEY)
						{
							delete _keysToControlMethods[_controlMethods[key].SecondaryKey];
						}

						// Add the new bind
						_keysToControlMethods[keyCode] = key;
						_controlMethods[key].SecondaryKey = keyCode;
						return;
					}
				}
			}

			if (_debug) LOGGER.debug("Failed to bind control method [" + funcName + "] to keyCode [" + keyCode + "]");
		}

		/**
		 * Remove an existing key from a BoundControlMethod, if present, and shuffle the remaining key as appropriate
		 * @param	keyCode		The keycode to remove.
		 */
		public function RemoveExistingKeyBind(keyCode:int):void
		{
			// If the key is already bound to a method, remove it from that method
			if (_keysToControlMethods[keyCode] != null)
			{
				if (_controlMethods[_keysToControlMethods[keyCode]].PrimaryKey == keyCode)
				{
					_controlMethods[_keysToControlMethods[keyCode]].PrimaryKey = _controlMethods[_keysToControlMethods[keyCode]].SecondaryKey;
					_controlMethods[_keysToControlMethods[keyCode]].SecondaryKey = InputManager.UNBOUNDKEY;
				}
				else if (_controlMethods[_keysToControlMethods[keyCode]].SecondaryKey == keyCode)
				{
					_controlMethods[_keysToControlMethods[keyCode]].SecondaryKey = InputManager.UNBOUNDKEY;
				}
			}
		}

		/**
		 * The core event handler we attach to the stage to capture incoming keyboard events.
		 * @param	e		KeyboardEvent data
		 */
		public function KeyHandler(e:KeyboardEvent):void
		{
			if (_debug) LOGGER.debug("Got key input " + e.keyCode);

			// Ignore key input during certain phases of gamestate
			if (_mainView.eventTestInput.x == 207.5)
			{
				return;
			}

			if (_mainView.nameBox.visible && _stage.focus == _mainView.nameBox)
			{
				return;
			}

			// If we're not in binding mode, listen for key inputs to act on
			if (_bindingMode == false)
			{
				// Made it this far, process the key and call the relevant (if any) function
				this.ExecuteKeyCode(e.keyCode);
			}
			// Otherwise, we're listening for a new keycode from the player
			else
			{
				BindKeyToControl(e.keyCode, _bindingFunc, _bindingSlot);
				StopListenForNewBind();
			}
		}

		/**
		 * Execute the BoundControlMethod's wrapped function associated with the given KeyCode
		 * @param	keyCode		The KeyCode for which we wish to execute the BoundControlMethod for.
		 */
		private function ExecuteKeyCode(keyCode:int):void
		{
			if (_keysToControlMethods[keyCode] != null)
			{
				if (_debug) LOGGER.debug("Attempting to exec func [" + _controlMethods[_keysToControlMethods[keyCode]].Name + "]");

				_controlMethods[_keysToControlMethods[keyCode]].ExecFunc();
			}

			for (var i:int = 0; i < _cheatControlMethods.length; i++)
			{
				_cheatControlMethods[i].ExecFunc(keyCode);
			}
		}

		/**
		 * Hide the mainText object and scrollbar, ensure the binding ScrollPane is up to date with the latest
		 * data and then show the binding scrollpane.
		 */
		public function DisplayBindingPane():void
		{
			_mainText.visible = false;

			_bindingPane.functions = this.GetAvailableFunctions();
			_bindingPane.ListBindingOptions();

			_mainText.parent.addChild(_bindingPane);
			_bindingPane.update();
		}

		/**
		 * Hide the binding ScrollPane, and re-display the mainText object + Scrollbar.
		 */
		public function HideBindingPane():void
		{
			_mainText.visible = true;
			_bindingPane.parent.removeChild(_bindingPane);
		}

		/**
		 * Register the current methods, and their associated bindings, as the defaults.
		 * TODO: Finish this shit off
		 */
		public function RegisterDefaults():void
		{
			for (var key:String in _controlMethods)
			{
				_defaultControlMethods[key] = new BoundControlMethod(
					_controlMethods[key].Func,
					_controlMethods[key].Name,
					_controlMethods[key].Description,
					_controlMethods[key].Index,
					_controlMethods[key].PrimaryKey,
					_controlMethods[key].SecondaryKey);
			}

			// Elbullshito mode -- 126 is the maximum keycode in as3 we're likely to see
			for (var i:int = 0; i <= 126; i++)
			{
				if (_keysToControlMethods[i] != undefined)
				{
					_defaultKeysToControlMethods[i] = _keysToControlMethods[i];
				}
			}
		}

		/**
		 * Reset the bound keys to the defaults previously registered.
		 */
		public function ResetToDefaults():void
		{
			for (var key:String in _controlMethods)
			{
				_controlMethods[key] = new BoundControlMethod(
					_defaultControlMethods[key].Func,
					_defaultControlMethods[key].Name,
					_defaultControlMethods[key].Description,
					_defaultControlMethods[key].Index,
					_defaultControlMethods[key].PrimaryKey,
					_defaultControlMethods[key].SecondaryKey);
			}

			// Elbullshito mode -- 126 is the maximum keycode in as3 we're likely to see
			for (var i:int = 0; i <= 126; i++)
			{
				if (_defaultKeysToControlMethods[i] != undefined)
				{
					_keysToControlMethods[i] = _defaultKeysToControlMethods[i];
				}
			}
		}

		/**
		 * Get an array of the available functions.
		 * @return	Array of available BoundControlMethods.
		 */
		public function GetAvailableFunctions():Array
		{
			var funcs:Array = new Array();

			for (var key:String in _controlMethods)
			{
				if (_debug) LOGGER.debug(key);
				funcs.push(_controlMethods[key]);
			}
			funcs.sortOn( ["Index"], [Array.NUMERIC] );

			return funcs;
		}

		/**
		 * Get an array of the currently active keyCodes.
		 * @return	Array of active keycodes.
		 */
		public function GetControlMethods():Array
		{
			var buttons:Array = new Array();
			for (var key:* in _keysToControlMethods)
			{
				buttons.push(key);
			}

			return buttons;
		}

		/**
		 * Clear all currently bound keys.
		 */
		public function ClearAllBinds():void
		{
			for (var key:String in _controlMethods)
			{
				_controlMethods[key].PrimaryKey = InputManager.UNBOUNDKEY;
				_controlMethods[key].SecondaryKey = InputManager.UNBOUNDKEY;
			}

			_keysToControlMethods = new Object();
		}

		/**
		 * Load bindings from a source "Object" retrieved from a game save file.
		 * @param	source	Source object to enumerate for binding data.
		 */
		public function LoadBindsFromObj(source:Object):void
		{
			this.ClearAllBinds();

			for (var key:String in source)
			{
				var pKeyCode:int = source[key].PrimaryKey;
				var sKeyCode:int = source[key].SecondaryKey;

				if (pKeyCode != InputManager.UNBOUNDKEY)
				{
					this.BindKeyToControl(pKeyCode, key, InputManager.PRIMARYKEY);
				}

				if (sKeyCode != InputManager.UNBOUNDKEY)
				{
					this.BindKeyToControl(sKeyCode, key, InputManager.SECONDARYKEY);
				}
			}
		}

		/**
		 * Create an associative object that can serialise the bindings to the users save file.
		 * @return	Dynamic object of control bindings.
		 */
		public function SaveBindsToObj():Object
		{
			var controls:Object = new Object();

			for (var key:String in _controlMethods)
			{
				if (_debug) LOGGER.debug(key);
				var ctrlObj:* = new Object();
				ctrlObj.PrimaryKey = _controlMethods[key].PrimaryKey;
				ctrlObj.SecondaryKey = _controlMethods[key].SecondaryKey;

				controls[key] = ctrlObj;
			}

			return controls;
		}
	}

	/**
	 * List of known bound keyboard methods
	 *
	 * Some of the methods use an undefined "Event" parameter to pass into the actual UI components...
	 * ... strip this out and instead modify the handlers on the execution end to have a default null parameter?
	 *
	 * ** Bypass handler if mainView.eventTestInput.x == 270.5
	 * ** Bypass handler if mainView.nameBox.visible && stage.focus == mainView.nameBox
	 *
	 * 38	-- UpArrow			-- Cheat code for Humus stage 1
	 * 40	-- DownArrow		-- Cheat code for Humus stage 2
	 * 37 	-- LeftArrow		-- Cheat code for Humus stage 3
	 * 39	-- RightArrow		-- Cheat code for Humus stage 4 IF str > 0, not gameover, give humus
	 *
	 * 83	-- s				-- Display stats if main menu button displayed
	 * 76	-- l				-- Level up if level up button displayed
	 * 112	-- F1				-- Quicksave to slot 1 if menu_data displayed
	 * 113	-- F2				-- Quicksave slot 2
	 * 114	-- F3				-- Quicksave slot 3
	 * 115	-- F4				-- Quicksave slot 4
	 * 116	-- F5				-- Quicksave slot 5
	 *
	 * 117	-- F6				-- Quickload slot 1
	 * 118	-- F7				-- Quickload slot 2
	 * 119	-- F8				-- Quickload slot 3
	 * 120	-- F9				-- Quickload slot 4
	 * 121	-- F10				-- Quickload slot 5
	 *
	 * 8	-- Backspace		-- Go to "Main" menu if in game
	 * 68	-- d				-- Open saveload if in game
	 * 65	-- a				-- Open apperance if in game
	 * 78	-- n				-- "no" if button index 1 displays no		<--
	 * 89	-- y				-- "yes" if button index 0 displays yes		<-- These two seem akward
	 * 80	-- p				-- display perks if in game
	 *
	 * 13/32 -- Enter/Space		-- if button index 0,4,5,9 or 14 has text of (nevermind, abandon, next, return, back, leave, resume) execute it
	 *
	 * 36	-- Home				-- Cycle the background of the maintext area
	 *
	 * 49	-- 1				-- Execute button index 0 if visisble
	 * 50	-- 2				-- ^ index 1
	 * 51	-- 3				-- ^ index 2
	 * 52	-- 4				-- ^ index 3
	 * 53	-- 5				-- ^ index 4
	 * 54/81-- 6/q				-- ^ index 5
	 * 55/87-- 7/w				-- ^ index 6
	 * 56/69-- 8/e				-- ^ index 7
	 * 57/82-- 9/r				-- ^ index 8
	 * 48/84-- 0/t				-- ^ index 9
	 *
	 * 68	-- ???				-- ??? Unknown, theres a conditional check for the button, but no code is ever executed
	 */
}


code:
package classes
{
	public class ItemSlot extends Object
	{
		//constructor
		public function ItemSlot()
		{
		}

		//data
		private var _quantity:int = 0;
		private var _itype:ItemType = ItemType.NOTHING;
		private var _unlocked:Boolean = false;
		private var _damage:int = 0; //Used for durability

		public function setItemAndQty(itype:ItemType, quant:int):void
		{
			if (itype == null) itype = ItemType.NOTHING;
			if (quant == 0 && itype == ItemType.NOTHING) {
				emptySlot();
				return;
			}
			if (quant<0 || quant == 0 && itype != ItemType.NOTHING || quant>0 && itype == ItemType.NOTHING){
				CoC_Settings.error("Inconsistent setItemAndQty call: "+quant+" "+itype);
				quant = 0;
				itype = ItemType.NOTHING;
			}
			this._quantity = quant;
			this._itype = itype;
		}

		public function emptySlot():void
		{
			this._quantity = 0;
			this._itype = ItemType.NOTHING;
		}

		public function removeOneItem():void
		{
			if (this._quantity == 0)
				CoC_Settings.error("Tried to remove item from empty slot!");
			if (this._quantity > 0)
				this._quantity -= 1;

			if (this._quantity == 0)
				this._itype = ItemType.NOTHING;
		}

		public function get quantity():int {
			return _quantity;
		}

		public function set quantity(value:int):void {
			if (value > 0 && _itype == null) CoC_Settings.error("ItemSlot.quantity set with no item; use setItemAndQty instead!");
			if (value == 0) _itype = ItemType.NOTHING;
			_quantity = value;
		}

		public function get itype():ItemType {
			return _itype;
		}

		public function get unlocked():Boolean {
			return _unlocked;
		}
		public function set unlocked(value:Boolean):void {
			if (_unlocked != value){
				emptySlot();
			}
			_unlocked = value;
		}

		public function isEmpty():Boolean
		{
			return _quantity<=0;
		}

		public function set damage(value:int):void {
			this._damage = value;
		}
		public function get damage():int {
			return this._damage;
		}
	}
}


code:
/**
 * Created by aimozg on 09.01.14.
 */
package classes
{
import classes.Items.Weapon;
import classes.Items.WeaponLib;
import classes.internals.Utils;
	import flash.utils.Dictionary;

	public class ItemType extends BaseContent
	{
		private static var ITEM_LIBRARY:Dictionary = new Dictionary();
		// private static var ITEM_SHORT_LIBRARY:Dictionary = new Dictionary();
		public static const NOTHING:ItemType = new ItemType("NOTHING!");

		/**
		 * Looks up item by ID.
		 * @param	id 7-letter string that identifies an item.
		 * @return  ItemType
		 */
		public static function lookupItem(id:String):ItemType{
			return ITEM_LIBRARY[id] || WeaponLib.BOOSTED_WEAPONS[id];
		}

		/**
		 * Looks up item by shortName.
		 * @param	shortName The short name that was displayed on buttons.
		 * @return  ItemType
		 */
		// public static function lookupItemByShort(shortName:String):ItemType{
			// return ITEM_SHORT_LIBRARY[shortName];
		// }

		public static function getItemLibrary():Dictionary
		{
			return ITEM_LIBRARY;
		}

		private var _id:String;
		protected var _shortName:String;
		protected var _longName:String;
		public var _description:String;
		protected var _value:Number;

		protected var _degradable:Boolean = false; //True indicates degrades in durability.
		protected var _durability:Number = 0; //If it's greater than 0, when threshold is crossed, it will cause item to break.
		protected var _breaksInto:ItemType = null; //If the weapon breaks, turns into the specific item or vanish into nothing.

		/**
		 * Short name to be displayed on buttons
		 */
		public function get shortName():String
		{
			return _shortName;
		}

		/**
		 * A full name of the item, to be described in text
		 */
		public function get longName():String
		{
			return _longName;
		}

		/**
		 * Item base price
		 */
		public function get value():Number
		{
			return _value;
		}

		/**
		 * Detailed description to use on tooltips
		 */
		public function get description():String
		{
			return _description;
		}

		/**
		 * 7-character unique (across all the versions) string, representing that item type.
		 */
		public function get id():String
		{
			return _id;
		}

		public function ItemType(_id:String = "",_shortName:String="",_longName:String="",_value:Number=0,_description:String="")
		{

			this._id = _id;
			this._shortName = _shortName || _id;
			this._longName = _longName || this.shortName;
			this._description = _description || this.longName;
			this._value = _value;
			if (ITEM_LIBRARY[_id] != null) {
				CoC_Settings.error("Duplicate itemid "+_id+", old item is "+(ITEM_LIBRARY[_id] as ItemType).longName);
			}
			// if (ITEM_SHORT_LIBRARY[this.shortName] != null){
				// CoC_Settings.error("WARNING: Item with duplicate shortname: '"+_id+"' and '"+(ITEM_SHORT_LIBRARY[this.shortName] as ItemType)._id+"' share "+this.shortName);
                // return;
			// }
			ITEM_LIBRARY[_id] = this;
			// ITEM_SHORT_LIBRARY[this.shortName] = this;
		}

		protected function appendStatsDifference(diff:int):String {
			if (diff > 0)
				return " (+" + String(Math.abs(diff)) + ")";
			else if (diff < 0)
				return " (-" + String(Math.abs(diff)) + ")";
			else
				return "";
		}

		public function toString():String
		{
			return "\""+_id+"\"";
		}

		public function getMaxStackSize():int {
			return 5;
		}

		//Durability & Degradation system
		public function isDegradable():Boolean {
			return this._degradable;
		}

		public function set durability(newValue:int):void {
			if (newValue > 0) this._degradable = true;
			this._durability = newValue;
		}
		public function get durability():int {
			return this._durability;
		}

		public function set degradesInto(newValue:ItemType):void {
			this._breaksInto = newValue;
		}
		public function get degradesInto():ItemType {
			return this._breaksInto;
		}

        public function set id(value:String):void {
            _id = value;
        }

        public function set shortName(value:String):void {
            _shortName = value;
        }

        public function set longName(value:String):void {
            _longName = value;
        }

        public function set description(value:String):void {
            _description = value;
        }

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

        public function set degradable(value:Boolean):void {
            _degradable = value;
        }

        public var bonusStats:BonusDerivedStats = new BonusDerivedStats();
        public var host:Creature;
        public var isAltered:Boolean = false;

        public function boostStat(stat:String,amount:*,mult:Boolean = false):void{
            bonusStats.boostStat(stat,amount,mult,longName);
        }

        public function boostsDodge(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.dodge,value,mult);
            return this;
        }

        public function boostsCritChance(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.critC,value,mult);
            return this;
        }

        public function boostsCritDamage(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.critD,value,mult);
            return this;
        }

        public function boostsWeaponDamage(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.weaponDamage,value,mult);
            return this;
        }

        public function boostsSpellMod(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.spellMod,value,mult);
            return this;
        }

        public function boostsMaxHealth(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.maxHealth,value,mult);
            return this;
        }

        public function boostsAccuracy(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.accuracy,value,mult);
            return this;
        }

        public function boostsSpellCost(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.spellCost,value,mult);
            return this;
        }

        public function boostsPhysDmg(value:*,mult:Boolean = false):*{
            boostStat(BonusDerivedStats.physDmg,value,mult);
            return this;
        }

        public function boostsHealthRegenPercentage(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.healthRegenPercent,value,mult);
            return this;
        }

        public function boostsHealthRegenFlat(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.healthRegenFlat,value,mult);
            return this;
        }

        public function boostsMinLust(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.minLust,value,mult);
            return this;
        }

        public function boostsSeduction(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.seduction,value,mult);
            return this;
        }

        public function boostsSexiness(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.sexiness,value,mult);
            return this;
        }

        public function boostsLustResistance(value:*, mult:Boolean = false):*{
            boostStat(BonusDerivedStats.lustRes,value,mult);
            return this;
        }
	}
}


code:
/**
 * Created by aimozg on 10.01.14.
 */
package classes.Items
{
	import classes.PerkLib;
	import classes.FetishManager;
	public class Armor extends Useable //Equipable
	{
		public static const WEIGHT_LIGHT:String = "Light";
		public static const WEIGHT_MEDIUM:String = "Medium";
		public static const WEIGHT_HEAVY:String = "Heavy";

		private var _def:Number;
		private var _perk:String;
		private var _name:String;
		private var _supportsBulge:Boolean;
		private var _supportsUndergarment:Boolean;
		private var _tier:int = 0; //Defaults to 0.

		public function Armor(id:String, shortName:String, name:String, longName:String, def:Number, value:Number = 0, description:String = null, perk:String = "", supportsBulge:Boolean = false, supportsUndergarment:Boolean = true) {
			super(id, shortName, longName, value, description);
			this._name = name;
			this._def = def;
			this._perk = perk;
			_supportsBulge = supportsBulge;
			_supportsUndergarment = supportsUndergarment;
		}

		public function get def():Number { return _def + _tier; }

		public function get perk():String { return _perk; }

		public function get name():String { return _name; }

		public function get supportsBulge():Boolean { return _supportsBulge && player.modArmorName == ""; }
			//For most clothes if the modArmorName is set then it's Exgartuan's doing. The comfortable clothes are the exception, they override this function.

		public function get supportsUndergarment():Boolean { return _supportsUndergarment; }

		override public function get description():String {
			var desc:String = _description;
			//Type
			desc += "\n\nType: ";
			if (perk == "Light" || perk == "Medium" || perk == "Heavy") {
				desc += "Armor (" + perk + ")";
			} else if (perk == "Adornment") desc += "Adornment ";
			else desc += "Clothing ";
			//Defense
			desc += "\nDefense: " + String(def);
			desc += appendStatsDifference(def - (player.armor.def));
			//Value
			desc += "\nBase value: " + String(value);
			desc += generateStatsTooltip();
			return desc;
		}

		override public function canUse():Boolean {
			if (player.armor.id == armors.VINARMR.id) {
				if (this == armors.GOOARMR) {
					outputText(armors.VINARMR.saveContent.armorStage > 2 ? "[say: Woah,] the sapphire ooze says, putting her hands up. [say: I'm not sure I want to lay on a bed of thorns.] How thorns can pose that much discomfort to amorphous goo is a mystery, but she does look visibly put-off by it. [say: Also, those vines aren't going to start drinking up all my fluids, will they?]" : "[say: Those vines aren't going to start drinking up all my fluids, will they?]] Valeria asks, concerned. The vines aren't killing you, you think, so it can't be that bad. [say: You're not a slime, partner, you aren't made of pure gooey nutrition for some plant-parasite to gobble up.]");
					outputText("\n\nAll you can really do is sigh and accept her refusal.")
				} else outputText("You attempt to put on your " + name + ", but the instant a bit of it presses down on your vines, a terrible burning sensation shoots across your [skinshort]. This plant does not like being covered.");
				return false;
			}
			if (this.supportsUndergarment == false && (player.upperGarment != UndergarmentLib.NOTHING || player.lowerGarment != UndergarmentLib.NOTHING)) {
				var output:String = "";
				var wornUpper:Boolean = false;

				output += "It would be awkward to put on " + longName + " when you're currently wearing ";
				if (player.upperGarment != UndergarmentLib.NOTHING) {
					output += player.upperGarment.longName;
					wornUpper = true;
				}

				if (player.lowerGarment != UndergarmentLib.NOTHING) {
					if (wornUpper) {
						output += " and ";
					}
					output += player.lowerGarment.longName;
				}

				output += ". You should consider removing them. You put it back into your inventory.";

				outputText(output);
				return false;
			}
			return super.canUse();
		}

		override public function useText():void {
			outputText("You equip " + longName + ".  ");
		}

		public function playerEquip():Armor { //This item is being equipped by the player. Add any perks, etc. - This function should only handle mechanics, not text output
			player.addToWornClothesArray(this);
			return this;
		}

		public function playerRemove():Armor { //This item is being removed by the player. Remove any perks, etc. - This function should only handle mechanics, not text output
			while (player.findPerk(PerkLib.BulgeArmor) >= 0) player.removePerk(PerkLib.BulgeArmor); //TODO remove this Exgartuan hack
			if (player.modArmorName.length > 0) player.modArmorName = "";
			return this;
		}

		public function removeText():void {} //Produces any text seen when removing the armor normally

		override public function getMaxStackSize():int {
			return 1;
		}

        override public function boostStat(stat:String,amount:*,mult:Boolean = false):void{
            bonusStats.boostStat(stat,amount,mult,name);
        }
	}
}


code:
/**
 * Created by aimozg on 10.01.14.
 */
package classes.Items
{
	import classes.Items.Armors.*;
	import classes.PerkLib;
	import classes.PerkType;

	public final class ArmorLib
	{
		public static const COMFORTABLE_UNDERCLOTHES:Armor = new ComfortableUnderclothes();
		public static const NOTHING:Armor = new Nothing();

		//Clothing
		public const ADVCLTH:Armor = new Armor("AdvClth","G. Clothes","green adventurer's clothes","a green adventurer's outfit, complete with pointed cap",2,200,"A set of comfortable green adventurer's clothes.  It even comes complete with a pointy hat!","Light");
		public const B_DRESS:Armor = new Armor("B.Dress","Long Dress","long ballroom dress patterned with sequins","a ballroom dress patterned with sequins",0,1200,"A long ballroom dress patterned with sequins.  Perfect for important occasions.","Medium");
		public const BIMBOSK:BimboSkirt = new BimboSkirt();
		public const BONSTRP:Armor = new Armor("BonStrp","BonStrp","barely-decent bondage straps","a set of bondage straps",0,600,"These leather straps and well-placed hooks are actually" +
				" designed in such a way as to be worn as clothing.  While they technically would cover your naughty bits, virtually every other inch of your body would be exposed.","Light",false,false).boostsSeduction(8).boostsSexiness(8);
		public const C_CLOTH:ComfortableClothes = new ComfortableClothes();
		public const CLSSYCL:Armor = new Armor("ClssyCl", "Suitclothes", "classy suitclothes", "a set of classy suit-clothes", 1, 400, "A set of classy suitclothes.", "Light");
		public const KIMONO :Armor = new Armor("Kimono ","Kimono ","kimono","a traditional kimono",2,500,"This is a type of robes also known as kimono traditionally worn by the people of the far East. It's pretty elegant.","Light");
		public const LTHRPNT:Armor = new Armor("LthrPnt","T.Lthr Pants","white silk shirt and tight leather pants","a pair of leather pants and a white silk shirt",0,450,"A flowing silk shirt and tight black leather pants.  Suave!","Light");
		public const M_ROBES:Armor = new Armor("M.Robes","Robes","modest robes","a set of modest robes",0,120,"A set of modest robes, not dissimilar from what the monks back home would wear.","Light");
		public const NURSECL:Armor = new Armor("NurseCl","NurseCl","skimpy nurse's outfit","a nurse's outfit",0,800,"This borderline obscene nurse's outfit would barely cover your hips and" +
				" crotch.  The midriff is totally exposed, and the white top leaves plenty of room for cleavage.  A tiny white hat tops off the whole ensemble.  It would grant a small regeneration" +
				" to your HP.","Light").boostsSeduction(8).boostsHealthRegenPercentage(1).boostsSexiness(8);
		public const OVERALL:Armor = new Armor("Overall", "Overalls", "white shirt and overalls", "a white shirt and overalls", 0, 60, "A simple white shirt and overalls.", "Light", true);
		public const R_BDYST:Armor = new Armor("R.BdySt","R.BdySt","red, high-society bodysuit","a red bodysuit for high society",1,1200,"A high society bodysuit. It is as easy to mistake it for ballroom apparel as it is for boudoir lingerie. The thin transparent fabric is so light and airy that it makes avoiding blows a second nature.","Light", true, false);
		public const RBBRCLT:Armor = new Armor("RbbrClt","Rbbr Fetish","rubber fetish clothes","a set of revealing rubber fetish clothes",3,1000,"A revealing set of fetish-wear.","Light",true, false).boostsSeduction(8).boostsSexiness(8);
		public const S_SWMWR:SluttySwimwear = new SluttySwimwear();
		public const T_BSUIT:Armor = new Armor("T.BSuit","Bodysuit","semi-transparent bodysuit","a semi-transparent, curve-hugging bodysuit",0,1300,"A semi-transparent bodysuit. It looks" +
				" like it will cling to all the curves of your body.","Light").boostsSeduction(7).boostsSexiness(7);
		public const TUBETOP:Armor = new Armor("TubeTop","Tube Top","tube top and short shorts","a snug tube top and VERY short shorts",0,80,"A clingy tube top and VERY short shorts.","Light");

		//Armour
		public const BEEARMR:Armor = new BeeArmor();
		public const BESTIAL:Armor = new BestialArmor();
		public const CHBIKNI:Armor = new Armor("ChBikni","Chn Bikini","revealing chainmail bikini","a chainmail bikini",2,700,"A revealing chainmail bikini that barely covers anything.  The" +
				" bottom half is little more than a triangle of metal and a leather thong.","Light", false, false).boostsSeduction(5).boostsSexiness(5);;
		public const DBARMOR:Armor = new PureMaraeArmor();
		public const DMNHIDE:Armor = new DemonhideArmor();
		public const DSCLARM:Armor = new Armor("DSclArm", "D.Scale Armor", "dragonscale armor", "a suit of dragonscale armor", 18, 900, "This armor is cleverly fashioned from dragon scales. It offers high protection while at the same time, quite flexible.", "Medium");
		public const DSCLROB:Armor = new Armor("DSclRob", "D.Scale Robes", "dragonscale robes", "a dragonscale robe", 9, 900, "This robe is expertly made from dragon scales. It offers high" +
				" protection while being lightweight, and should be comfortable to wear all day.", "Light").boostsSpellCost(-20);
		public const EBNARMR:Armor = new Armor("EWPlate", "EW Plate", "Ebonweave Platemail", "a set of Ebonweave Platemail", 27, 3000, "The armor is made of ebonweave, created using refined" +
				" Ebonbloom petals. The armor consists of two layers: an outer of ebonweave plating and an inner of arrow-proof ebonweave cloth.", "Heavy").boostsSpellCost(-15);
		public const EBNJACK:Armor = new Armor("EWJackt", "EW Jacket", "Ebonweave Jacket", "an Ebonweave Jacket", 18, 3000, "This outfit is made of ebonweave, created using refined" +
				" Ebonbloom petals. The outfit consists of a leather-like jacket, a mesh breastplate, and a set of arrow-proof clothing.", "Medium").boostsSpellCost(-15);
		public const EBNROBE:Armor = new Armor("EW Robe", "EW Robe", "Ebonweave Robe", "an Ebonweave Robe", 9, 3000, "This robe is made of ebonweave, a material created using refined" +
				" Ebonbloom petals. This robe is comfortable, yet more protective than chainmail. It has a mystical aura to it.", "Medium").boostsSpellCost(-30);
		public const EBNIROB:Armor = new Armor("EWIRobe", "EW I.Robe", "indecent Ebonweave Robe", "an indecent Ebonweave Robe", 6, 3000, "More of a longcoat than a robe, this outfit is crafted from" +
				" refined Ebonbloom petals. Discrete straps centered around the belt keep the front open.", "Light",true).boostsSpellCost(-30).boostsSeduction(5).boostsSexiness(5);
		public const FULLCHN:Armor = new Armor("FullChn","Full Chain","full-body chainmail","a full suit of chainmail armor",8,150,"This full suit of chainmail armor covers its wearer from head to toe in protective steel rings.","Medium");
		public const FULLPLT:Armor = new Armor("FullPlt","Full Plate","full platemail","a suit of full-plate armor",21,250,"A highly protective suit of steel platemail.  It would be hard to find better physical protection than this.","Heavy");
		public const GELARMR:Armor = new Armor("GelArmr","GelArmr","glistening gel-armor plates","a suit of gel armor",10,150,"This suit of interlocking plates is made from a strange green material.  It feels spongy to the touch but is amazingly resilient.","Heavy");
		public const GOLARMR:Armor = new Armor("GolArmr","GolArmr","Obsidian golem full-plate armor","a suit of golem armor",30,3000,"This full suit of armor was fashioned from a golem's heart, and provides excellent defense.","Heavy");
		public const GOOARMR:GooArmor = new GooArmor();
		public const I_CORST:InquisitorsCorset = new InquisitorsCorset();
		public const I_ROBES:InquisitorsRobes = new InquisitorsRobes();
		public const INDECST:Armor = new Armor("IndecSt","Indec StAr","practically indecent steel armor","a suit of practically indecent steel armor",5,800,"This suit of steel 'armor' has" +
				" two round disks that barely cover the nipples, a tight chainmail bikini, and circular butt-plates.","Medium").boostsSeduction(6).boostsSexiness(6);
		public const LEATHRA:Armor = new Armor("LeathrA","LeathrA","leather armor segments","a set of leather armor",5,76,"This is a suit of well-made leather armor.  It looks fairly rugged.","Light");
		public const NNUNHAB:NaughtyNunsHabit = new NaughtyNunsHabit();
		public const URTALTA:LeatherArmorSegments = new LeatherArmorSegments();
		public const LMARMOR:LustyMaidensArmor = new LustyMaidensArmor();
		public const LTHCARM:LethiciteArmor = new LethiciteArmor();
		public const LTHRROB:Armor = new Armor("LthrRob","Lthr Robes","black leather armor surrounded by voluminous robes","a suit of black leather armor with voluminous robes",6,100,"This is a suit of flexible leather armor with a voluminous set of concealing black robes.","Light");
		public const NQGOWN:Armor = new NephilaQueensGown();
		public const TBARMOR:Armor = new MaraeArmor();
		public const SAMUARM:Armor = new Armor("SamuArm","Samu.Armor","samurai armor","a suit of samurai armor",18,300,"This suit of armor is originally worn by the Samurai, the warriors from the far East.","Heavy");
		public const SCALEML:Armor = new Armor("ScaleMl","Scale Mail","scale-mail armor","a set of scale-mail armor",12,170,"This suit of scale-mail covers the entire body with layered steel scales, providing flexibility and protection.","Heavy");
		public const SEDUCTA:SeductiveArmor = new SeductiveArmor();
		public const SEDUCTU:SeductiveArmorUntrapped = new SeductiveArmorUntrapped();
		public const SS_ROBE:Armor = new Armor("SS.Robe","SS.Robes","spider-silk robes","a spider-silk robes",6,950,"This robe looks incredibly comfortable.  It's made from alchemically" +
				" enhanced spider-silk, and embroidered with what looks like magical glyphs around the sleeves and hood.","Light").boostsSpellCost(-30);
		public const SSARMOR:Armor = new Armor("SSArmor","SS.Armor","spider-silk armor","a suit of spider-silk armor",25,950,"This armor is as white as the driven snow.  It's crafted out of thousands of strands of spider-silk into an impenetrable protective suit.  The surface is slightly spongy, but so tough you wager most blows would bounce right off.","Heavy");
		public const W_ROBES:Armor = new Armor("W.Robes","W.Robes","wizard's robes","a wizard's robes",1,50,"These robes appear to have once belonged to a female wizard.  They're long with" +
				" a slit up the side and full billowing sleeves.  The top is surprisingly low cut.  Somehow you know wearing it would aid your spellcasting.","Light").boostsSpellCost(-25);
		public const FRSGOWN:Gown = new Gown();
		public const YORHARM:ArmorWithPerk = new ArmorWithPerk("Y.Armor", "Y.Armor", "Yorham Scout Armor", "a Yorham Scout Armor", 5, 2000, "This intricately designed armor is used by Yorham's scouts, who have to be quick on their feet and wits. Straps and holsters for vials and various other tools are spread throughout the many straps and belts, allowing for quick access. The thick, black leather offers poor protection, however.", "Light", PerkLib.QuickPockets, 0, 0, 0, 0, "The first item used in a turn does not end it.");
		public const VINARMR:VineArmor = new VineArmor();

		public function ArmorLib()
		{
		}
	}
}


code:
/**
 * Created by aimozg on 18.01.14.
 */
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.PerkType;
	import classes.PerkLib;
	import classes.Player;

	public class ArmorWithPerk extends Armor {
		private var playerPerk:PerkType;
		private var playerPerkV1:Number;
		private var playerPerkV2:Number;
		private var playerPerkV3:Number;
		private var playerPerkV4:Number;
		private var playerPerk2:PerkType;
		private var playerPerk2V1:Number;
		private var playerPerk2V2:Number;
		private var playerPerk2V3:Number;
		private var playerPerk2V4:Number;

		public function ArmorWithPerk(id:String, shortName:String,name:String, longName:String, def:Number, value:Number, description:String, perk:String, playerPerk:PerkType, playerPerkV1:Number, playerPerkV2:Number, playerPerkV3:Number, playerPerkV4:Number, playerPerkDesc:String = "", playerPerk2:PerkType = null, playerPerk2V1:Number = 0, playerPerk2V2:Number = 0, playerPerk2V3:Number = 0, playerPerk2V4:Number = 0, playerPerk2Desc:String = "", supportsBulge:Boolean = false, supportsUndergarment:Boolean = true) {
			super(id, shortName, name, longName, def, value, description, perk, supportsBulge, supportsUndergarment);
			this.playerPerk = playerPerk;
			this.playerPerkV1 = playerPerkV1;
			this.playerPerkV2 = playerPerkV2;
			this.playerPerkV3 = playerPerkV3;
			this.playerPerkV4 = playerPerkV4;
			this.playerPerk2 = playerPerk2;
			this.playerPerk2V1 = playerPerk2V1;
			this.playerPerk2V2 = playerPerk2V2;
			this.playerPerk2V3 = playerPerk2V3;
			this.playerPerk2V4 = playerPerk2V4;
		}

		override public function playerEquip():Armor { //This item is being equipped by the player. Add any perks, etc.
			while (player.findPerk(playerPerk) >= 0) player.removePerk(playerPerk);
			player.createPerk(playerPerk, playerPerkV1, playerPerkV2, playerPerkV3, playerPerkV4);
			if (playerPerk2 != null && player.findPerk(playerPerk2) >= 0) player.removePerk(playerPerk2);
			if (playerPerk2 != null) player.createPerk(playerPerk2, playerPerk2V1, playerPerk2V2, playerPerk2V3, playerPerk2V4);
			return super.playerEquip();
		}

		override public function playerRemove():Armor { //This item is being removed by the player. Remove any perks, etc.
			while (player.findPerk(playerPerk) >= 0) player.removePerk(playerPerk);
			if (playerPerk2 != null && player.findPerk(playerPerk2) >= 0) player.removePerk(playerPerk2);
			return super.playerRemove();
		}

		override public function get description():String {
			var desc:String = super.description;
			//Perk
			desc += "\nSpecials: " + playerPerk.name;
			if (playerPerk == PerkLib.WizardsEndurance) desc += " (-" + playerPerkV1 + "% Spell Cost)";
			else if (playerPerkV1 > 0) desc += " (Magnitude: " + playerPerkV1 + ")";
			//Second perk
			if (playerPerk2 != null) {
				desc += "\n" + playerPerk2.name;
				if (playerPerk2 == PerkLib.WizardsEndurance) desc += " (-" + playerPerk2V1 + "% Spell Cost)";
				else if (playerPerk2V1 > 0) desc += " (Magnitude: " + playerPerk2V1 + ")";
			}
			return desc;
		}

/*
		override public function equipEffect(player:Player, output:Boolean):void
		{
			if (player.findPerk(playerPerk) < 0)
				player.createPerk(playerPerk,playerPerkV1,playerPerkV2,playerPerkV3,playerPerkV4);
		}

		override public function unequipEffect(player:Player, output:Boolean):void
		{
			while(player.findPerk(playerPerk) >= 0) player.removePerk(playerPerk);
		}
*/
	}
}


code:
package classes.Items.Armors
{
	import classes.FetishManager;
	import classes.GlobalFlags.kFLAGS;
	import classes.ItemType;
	import classes.Items.Armor;
	import classes.Player;
	import classes.BodyParts.*;

	public class BeeArmor extends Armor
	{
		public function BeeArmor()
		{
			super("BeeArmr","Bee Armor","sexy black chitin armor-plating","a set of chitinous armor",18,200,"A suit of armor cleverly fashioned from giant bee chitin. It comes with a silken loincloth to protect your modesty.","Heavy");
		}

		override public function useText():void
		{
			outputText("You" + player.clothedOrNaked(" first strip yourself naked and ") + " equip your armor, one piece at a time. \n\nFirst, you clamber into the breastplate. ");
			if (player.isBiped()) //Some variants.
			{
				if (player.lowerBody.type == LowerBody.HUMAN) outputText("Then you put your feet into your boots. With the boots fully equipped, you move on to the next piece. ");
				else outputText("Then you attempt to put your feet into your boots. You realize that the boots are designed for someone with normal feet. You have to modify the boots to fit and when you do put on your boots, your feet are exposed. ");
			}
			outputText("Next, you put on your chitinous bracers to protect your arms.\n\n")
			if (!player.isTaur()) {
				outputText("Last but not least, you put your silken loincloth on to cover your groin. You thank Rathazul for that and you know that you easily have access to your ");
				if (player.hasCock()) outputText(player.multiCockDescriptLight());
				if (player.hasCock() && player.hasVagina()) outputText(" and ");
				if (player.hasVagina()) outputText(player.vaginaDescript());
				//Genderless
				if (!player.hasCock() && !player.hasVagina()) outputText("groin");
				outputText(" should you need to. ");
				if (player.hasCock())
				{
					if (player.biggestCockArea() >= 40 && player.biggestCockArea() < 100)
					{
						outputText("Large bulge forms against your silken loincloth. ");
					}
					if (player.biggestCockArea() >= 100)
					{
						outputText("Your manhood is too big to be concealed by your silken loincloth. Part of your " + player.cockDescriptShort(player.biggestCockIndex()) + " is visible. ");
						if (player.cor < 33) outputText("You let out a sigh. ");
						else if (player.cor >= 33 && player.cor < 66) outputText("You blush a bit, not sure how you feel. ");
						else if (player.cor >= 66 || game.fetishManager.compare(FetishManager.FETISH_EXHIBITION)) outputText("You admire how your manhood is visible. ");
					}
				}
				if (player.cor >= 66 || game.fetishManager.compare(FetishManager.FETISH_EXHIBITION))
				{
					outputText("You'd love to lift your loincloth and show off whenever you want to. ");
				}
			}
			else {
				outputText("Last but not least, you take a silken loincloth in your hand but stop short as you examine your tauric body. There is no way you could properly conceal your genitals! ");
				if (player.cor < 33) outputText("You let out a sigh. Being a centaur surely is inconvenient! ");
				else if (player.cor >= 33 && player.cor < 66) outputText("You blush a bit, not sure how you feel. ");
				else if (player.cor >= 66 || game.fetishManager.compare(FetishManager.FETISH_EXHIBITION)) outputText("Regardless, you are happy with what you are right now. ");
				outputText("You leave the silken loincloth in your possessions for the time being.");
			}
			outputText("\n\nYou admire the design of your armor. No wonder it looks so sexy!")
		}
	}
}


code:
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.PerkLib;

	public final class BestialArmor extends ArmorWithPerk {

		public function BestialArmor() {
			super("Bestial", "BeastArmor", "bestial armor", "a suit of jaguar hide armor", 9, 2000, "DESC", "Light", PerkLib.FeralBerserker, 0, 0, 0, 0);
		}

		override public function get description():String {
			var desc:String = super.description;
			//TODO: Show set bonus if claws equipped
			return desc;
		}
	}
}


code:
/**
 * Created by aimozg on 18.01.14.
 */
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.Items.ArmorLib;
	import classes.PerkLib;
	import classes.Player;
	import classes.Items.UndergarmentLib;

	public class BimboSkirt extends Armor {

		public function BimboSkirt() {
			super("BimboSk","BimboSk","bimbo skirt","A skirt that looks like it belongs on a bimbo",1,50,"A tight, cleavage-inducing halter top and an extremely short miniskirt.  The sexual allure" +
					" of this item is undoubtable.","Light",false,false);
			boostsSeduction(getSeductionLevel);
            boostsSexiness(getSeductionLevel);
		}

		public function getSeductionLevel():Number{
            var wornUpper:Boolean = (player.upperGarment != UndergarmentLib.NOTHING);
            var wornLower:Boolean = (player.lowerGarment != UndergarmentLib.NOTHING);
            // If player wears underwear with bimbo skirt, slutty seduction perks are severely reduced
			if (wornLower) {
				if (wornUpper) return 0;
				else return 1;
			}
			else {
				if (wornUpper) return 3;
				else return 10;
			}

		}

		override public function useText():void { //Produces any text seen when equipping the armor normally

			var wornUpper:Boolean = (player.upperGarment != UndergarmentLib.NOTHING);
			var wornLower:Boolean = (player.lowerGarment != UndergarmentLib.NOTHING);

			if (wornLower && wornLower) {
				outputText("You look very awkward wearing " + player.lowerGarment.longName + " while putting your skirt on.");
				outputText(" You realize that you probably won't be able to seduce many of your foes in this ludicrous outfit. For a moment you consider taking your " + player.lowerGarment.longName + " off, but then decide against it.");
				return;
			}

			dynStats("lus", 5);

			if (!wornUpper) {
				if (player.biggestTitSize() >= 8) {
					outputText("The halter top clings tightly to your bustline, sending a shiver of pleasure through your body. You feel how your erect [nipples] protrude from the soft fabric of your beautiful dress, and the sensation makes you feel slightly dizzy. ");
					if (player.isLactating()) {
						outputText("You feel how the top of your dress becomes wet, as droplets of milk leak from your [nipples]. ");
					}
				}
				else if (player.biggestTitSize() >= 5) {
					outputText("The halter top clings to your bustline, sending a shiver of pleasure through your body. ");
					if (player.isLactating()) {
						outputText("You feel how the top of your dress becomes wet, as droplets of milk leak from your [nipples]. ");
					}
					dynStats("lus", 2);
				}
				else if (player.biggestTitSize() >= 2) {
					outputText("The halter top of your sluttish outfit snugly embraces your " + player.breastDescript(0) + ". The sensation of the soft fabric on your bare [nipples] makes you feel warm and sexy. ");
					if (player.isLactating()) {
						outputText("You feel how the top of your dress becomes wet, as droplets of milk leak from your [nipples]. ");
					}
					dynStats("lus", 5);
				}
				else if (player.biggestTitSize() >= 1) {
					outputText("You feel how the soft fabric of your dress caresses your " + player.breastDescript(0) + ". The sensation is very erotic and you touch your sensitive [nipples], feeling the spread of arousal. You idly notice that the halter top of your whorish dress is somewhat loose, and it would feel much better if your breasts were bigger and suppler. ");
					if (player.isLactating()) {
						outputText("You feel how the top of your dress becomes wet, as droplets of milk leak from your [nipples]. ");
					}
					dynStats("lus", 10);
				}
				else {
					outputText("You feel rather stupid putting the top part on like this, but you're willing to bear with it. As you put it on, you feel how the soft fabric of your dress touches your [nipples], making them erect.");
					dynStats("lus", 15);
				}
				outputText("\n\n");
				player.orgasm('Tits',false);
			}

			if (!wornLower) {
				if (player.butt.rating < 8) {
					outputText("The sensation of tender fabric clinging to your [butt] arouses you immensely, as you smooth your skirt. ");
				}
				else {
					outputText("You can feel how the fine fabric of your sluttish skirt doesn't quite cover your [ass]");
					if (player.hips.rating > 8) {
						outputText(", and how the smooth skirt is stretched by your [hips]. ");
					}
					else outputText(". ");
				}
				if (player.hasCock()) {
					outputText("Your [cock] becomes erect under your obscene skirt, bulging unnaturally. ");
				}
				else if (player.hasVagina()) {
					switch (player.vaginas[0].vaginalWetness) {
						case 5:
							outputText("Your juice constantly escapes your [pussy] and spoils your sexy skirt. ");
							dynStats("lus", 5);
							break;
						case 4:
							outputText("A thin stream of your girl-cum escapes your [pussy] and spoils your skirt. ");
							dynStats("lus", 5);
							break;
						case 3:
							outputText("Your [pussy] becomes all tingly and wet under your slutty skirt. ");
							dynStats("lus", 5);
							break;
						default: //Move along
					}
				}
				if (player.gender == 0) {
					outputText("Despite your lack of features, you indeed feel arousal all over your body. ");
				}
				outputText("\n\n");
				player.orgasm('Anal', false);
				player.orgasm('Vaginal', false);
			}

			player.orgasm('Lips',false);
		}

		override public function get supportsUndergarment():Boolean {
			return player.isPureEnough(10);
		}

		override public function canUse():Boolean {

			var wornUpper:Boolean = player.upperGarment != UndergarmentLib.NOTHING;
			var wornLower:Boolean = player.lowerGarment != UndergarmentLib.NOTHING;

			if (player.armor.id == armors.VINARMR.id) {
				outputText("You attempt to put on your " + name + ", but the instant a bit of it presses down on your vines, a terrible burning sensation shoots across your [skinshort]. This plant does not like being covered.");
				return false;
			}

			if (!player.isPureEnough(10)) {
				if (wornUpper || wornLower) {
					var output:String = "";
					output += "It would be awkward to put on " + longName + " when you're currently wearing ";
					if (wornUpper) {
						output += player.upperGarment.longName;
						wornUpper = true;
					}
					if (wornLower) {
						if (wornUpper) {
							output += " and ";
						}
						output += player.lowerGarment.longName;
					}
					output += ". You should consider removing them. You put it back into your inventory.";
					outputText(output);
					return false;
				}
				else
					return true;
			}
			return true;
		}
	}

}


code:
/**
 * Created by aimozg on 18.01.14.
 */
package classes.Items.Armors
{
	import classes.ItemType;
	import classes.Items.Armor;
	import classes.Player;

	public class ComfortableClothes extends Armor {

		public function ComfortableClothes() {
			super("C.Cloth", "C.Cloth", "comfortable clothes", "a set of comfortable clothes", 0, 0, "These loose fitting and comfortable clothes allow you to move freely while protecting you from the elements.", "Light", true);
		}

		override public function get supportsBulge():Boolean { return player.modArmorName != "crotch-hugging clothes"; }
			//Comfortable clothes can't be changed by Exgartuan if he's already changed them

/*
		override protected function unequipReturnItem(player:Player,output:Boolean):ItemType
		{
			if (output && player.armorName != player.armor.name){
				outputText("The " + player.armorName + " revert into a pair of comfortable clothes, as if by magic.  ");
			}
			return this;
		}
*/
	}
}


code:
/**
 * Created by aimozg on 10.01.14.
 */
package classes.Items.Armors
{
	import classes.ItemType;
	import classes.Items.Armor;
	import classes.Player;

	public final class ComfortableUnderclothes extends Armor {

		public function ComfortableUnderclothes() {
			super("c.under", "c.under", "comfortable underclothes", "comfortable underclothes", 0, 0, "comfortable underclothes", "Light");
		}

		override public function playerRemove():Armor {
			return null; //Player never picks up their underclothes
		}
	}
}


code:
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.PerkLib;

	public final class DemonhideArmor extends ArmorWithPerk {

		public function DemonhideArmor() {
			super("DmnHide", "D.Hide Armor", "demonhide armor", "a suit of demonhide armor", 20, 2000, "desc", "Medium", PerkLib.DemonHunter, 0, 0, 0, 0);
		}

		override public function get description():String {
			var desc:String = super.description;
			//TODO: Show set bonus if shield equipped
			return desc;
		}
	}
}


code:
/**
 * Created by aimozg on 11.01.14.
 */
//Not used in game
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.Items.ArmorLib;

	public final class FurLoincloth extends Armor
	{
		public function FurLoincloth()
		{
			super("FurLoin","FurLoin","revealing fur loincloths","a front and back set of loincloths",0,100,"A pair of loincloths to cover your crotch and butt.  Typically worn by people named 'Conan'.","Light");
		}

		override public function get description():String
		{
			return "A pair of loincloths to cover your crotch and " + player.buttDescript() + ".  Typically worn by people named 'Conan'. \n\nType: Clothing \nDefense: 0 \nBase value: 100"
		}
	}
}


code:
/**
 * Created by aimozg on 16.01.14.
 */
package classes.Items.Armors
{
	import classes.GlobalFlags.kFLAGS;
	import classes.GlobalFlags.kACHIEVEMENTS;
	import classes.ItemType;
	import classes.Items.Armor;
	import classes.Player;

	public final class GooArmor extends Armor {

		public function GooArmor() {
			super("GooArmr","GooArmr","goo armor","Valeria, the goo-girl armor",22,1,"This shining suit of platemail is more than just platemail - it houses the goo-girl, Valeria!  Together, they provide one tough defense, but you had better be okay with having goo handling your junk while you fight if you wear this!","Heavy");
		}

		override public function useText():void { //Produces any text seen when equipping the armor normally
			outputText("With an ecstatic smile, the goo-armor jumps to her feet and throws her arms around your shoulders.  \"Oh, this is going to be so much fun!  Thank you thank you thank you!  I promise I'll keep you nice and snug and safe, don't you worry.  Oooh, a real adventure again!  WHEEE!\"");
			outputText("\n\nBefore she can get too excited, you remind the goo that she's supposed to be your armor right about now.  Clasping her hands over her mouth in embarrassment, she utters a muted apology and urges you to just \"put me on!\"  Awkwardly, you strip out of your gear and open up the platemail armor and clamber in.  It's wet and squishy, making you shudder and squirm as you squash your new friend flat against the metal armor.");
			outputText("\n\nEventually, the two of you get situated. The goo-girl slips around your body inside the heavy armor, maneuvering so that your face is unobstructed and your joints, not protected by the armor, are soundly clad in squishy goo.  She even forms a gooey beaver on your new helm, allowing you to open and close her like a visor in battle.  Eventually, her goo settles around your ");
			if (player.hasVagina()) outputText("[vagina]");
			if (player.hasVagina() && player.hasCock()) outputText(" and ");
			if (player.hasCock()) outputText(player.multiCockDescriptLight());
			if (player.gender == 0) outputText("groin");
			outputText(", encasing your loins in case you need a little mid-battle release, she says.");
			outputText("\n\nAfter a few minutes, you and your armor-friend are settled and ready to go.");
			if (flags[kFLAGS.MET_VALERIA] == 0) {
				outputText("  As you ready yourself for the " + (game.dungeons.checkPhoenixTowerClear() ? "adventures": "dungeon") + " ahead, the goo giggles into your ear.  \"Oh shit, silly me.  I forgot, my name's Valeria.  Ser Valeria, if you're feeling fancy.\"  You introduce yourself, awkwardly shaking your own hand by way of pleasantries.");
				flags[kFLAGS.MET_VALERIA]++;
			}
			outputText("\n\n\"Well alright then, [name]!\" Valeria says excitedly, \"Let's go!\"\n\n");
			awardAchievement("Goo Armor", kACHIEVEMENTS.GENERAL_GOO_ARMOR);
		}

		override public function removeText():void { //Produces any text seen when removing the armor normally
			outputText("Valeria picks herself up and huffs, \"Maybe we can adventure some more later on?\" before undulating off towards your camp.\n\n(Valeria now available in the followers tab!)");
		}

		override public function playerEquip():Armor { //This item is being equipped by the player. Add any perks, etc.
			flags[kFLAGS.VALARIA_AT_CAMP] = 0;
			return super.playerEquip();
		}

		override public function get def():Number {
			if (game.valeria.valeriaFluidsEnabled()) {
				if (flags[kFLAGS.VALERIA_FLUIDS] < 50) {
					return 15 + int(flags[kFLAGS.VALERIA_FLUIDS] / 5);
				}
				else return 25;
			}
			else return 22;
		}

		override public function playerRemove():Armor { //This item is being removed by the player. Remove any perks, etc.
			flags[kFLAGS.VALARIA_AT_CAMP] = 1;
			return null; //Can't put Valaria in your inventory
		}
	}
}


code:
//forest gown that has a slow progression to a dryad

package classes.Items.Armors
{
	import classes.GlobalFlags.kGAMECLASS;
	import classes.BodyParts.*;
	import classes.Items.Armor;
	import classes.Scenes.BimboProgression;
	import classes.TimeAwareInterface;
	import classes.lists.BreastCup;
	import classes.lists.Gender;
	import classes.CoC;

	public class Gown extends Armor implements TimeAwareInterface {

		public function Gown():void {
			super("FrsGown","FrsGown","forest gown","a forest gown",1,10,"This the very earthy gown commonly worn by dryads.  It is made from a mixture of plants.  The predominate fabric looks like a weave of fresh grass.  It is decorated by simple flowers that are attached to it.  Strangely, everything seems alive like it was still planted.  There must be some peculiar magic at work here.","Light");
			CoC.timeAwareClassAdd(this);
		}

		override public function useText():void{ //Produces any text seen when equipping the armor normally
			switch (player.gender) {
				case Gender.FEMALE:
					outputText("You comfortably slide into the forest gown.  You spin around several times and giggle happily."
					          +" Where did that come from?");
					break;

				case  Gender.MALE:
					outputText("You slide forest gown over your head and down to your toes. It obviously would fit someone more female."
					          +" You feel sad and wish you had the svelte body that would look amazing in this gown."
					          +" Wait, did you always think that way?");
			     break;
			  default :  //non-binary
				  outputText("You slide the gown over your head and slip it into place.");
			}
			if (player.hasCock())
				outputText(" You notice the bulge from your [cock] in the folds of the dress and wish it wasn't there.\n");
		}
		public function timeChangeLarge():Boolean { return false; }
		public function timeChange():Boolean {
			if (player.armor is Gown && time.hours == 5) { //only call function once per day as time change is called every hour
				dryadProgression();
				return true;
			}
			return false; //stop if not wearing
		}
		public function dryadProgression():void {
			var verb:String;
			var text:String;
			var changed:Boolean = false;
			var tfChoice:Array = [];
			var dryadDreams:Array = [
				"In your dream you find yourself in a lush forest standing next to a tree. The tree seems like your best friend and You give it a hug before sitting down next to it. Looking around, there is grass and flowers all about. You can’t help but hum a cheery tune enjoying nature as a bright butterfly flutters nearby, holding out your hand the butterfly lands softly on your finger and smile sweetly to it.",
				"You walk through a meadow and down towards a swift running brook, it looks like some clean water.   You sit down, pull up your gown and admire your feet. They are brown, the color of bark.   You place your feet in the cool water of the brook and soak up the water through your feet, a cool refreshing feeling fills your body. Ah, being a Dryad is so nice.",
				"Your imagination runs a bit wild and you picture yourself dressed in your nice forest gown eyeing a satyr you stumble across in a grove.   You can't help but smirk as you consider all the fun you could have with him.",
				"You imagine running into a waterfall. You dance around playfully while torrents of water splash against your body.  Your soaked gown scandalously clings to your frame.",
				"You dream about tending to plants in a meadow. Some faeries are following you.  One of them buzzes around your head playfully and kisses you on the cheek.",
				"In your dream you are laying out in a lush glade soaking up the sun. You inspect your leafy hair and find that here are some buds forming. You can't help but wonder what the flowers will look like. ",
				"You dream of a starlight dance in the meadow. Several satyrs, nymphs and dryads are gathered together to celebrate the full moon. You take your gown off and gather around the faerie circle. The half dozen naked revelers dance the night away in the pale moonlight.",
				"You dream of skipping joyfully through a flowered meadow. After a while you kneel down and pick several budding flowers, placing them in your hair  you find that they merge with the leafy vines. They will bloom in a day or so.  It will be so lovely.",
				"In your dream, you and another dryad dance for a reed playing satyr. The dance is very intimate and you can't help wonder how excited the satyr will become from watching. ",
				"You dream of being in a lush grove watching a satyr sleeping. He is leaning up against a tree that you are very fond of! Some mischief is in order. You politely ask the tree for help and it lowers several vines that lift you up and move you above him. The vine lowers you mere inches away from his body. You can practically hear him breathing and his chest rising and falling slowly.  Leaning forward, you nibble on his ear, jolting him awake with a surprised look in his eyes just in time to see the vines recede back into the tree.   Chuckling to yourself, you watch the satyr try to figure out what just happened from a branch above him. ",
				"You dream of being in a field surrounded by butterflies. There are blue ones, yellow ones, and pink ones, but which ones are your favorite?   You spin around in your gown and laugh as you decide they are all your favorite!",
				"You dream about wandering around in the mountains. There is snow everywhere, and you notice something off in the distance digging its way out from under the snow. It’s a big bear and two smaller ones pawing their way out! You gleefully saunter up and say, 'Hello Mrs. bear, did you and your children enjoy your nap?'   You awake shortly after the strange dream, feeling confused. Was that really you?",
				"You dream about sitting on a tree branch in your lovely gown. You freely hang off the large oak, dangling over the side while your legs hold you up.   Your gown falls down to your arms and hangs over your head. You get excited, pondering if someone might be watching and just got flashed.   You sit back up and straighten out your gown,  coy smile playing across your face.",
			];
			//display a random dream
			clearOutput();
			outputText(dryadDreams[rand(dryadDreams.length)]+"\n\n");
			var idealHips:int = (player.isChild() ? Hips.RATING_BOYISH : Hips.RATING_AVERAGE + 1);
			var idealButt:int = (player.isChild() ? Butt.RATING_BUTTLESS + 1 : Butt.RATING_AVERAGE + 1);
			var idealBreasts:int = (player.isChild() ? BreastCup.FLAT : BreastCup.D);
			var idealFem:int = (player.isChild() ? 56 : 70);
			//build a list of non ideal parts
			if (player.hips.rating != idealHips)
				 tfChoice.push("hips");
			if (player.butt.rating != idealButt)
				tfChoice.push("butt");
			if (player.hasCock())
				tfChoice.push("cock");
			if (player.breastRows[0].breastRating != idealBreasts || player.bRows() > 1)
				tfChoice.push("breasts");
			if (player.femininity < idealFem)
				tfChoice.push("girlyness");

			//progress slowly to the ideal dryad build
			switch (randomChoice(tfChoice)) {
				case "hips":
						outputText("You wiggle around in your gown, pleasant feeling of flower petals rubbing against your skin washes over you.  The feeling settles on your [hips].\n");
						if (player.hips.rating < idealHips) {
							verb = "enlarge";
							player.hips.rating++;
						} else {
							verb = "shrink";
							player.hips.rating--;
						}
						outputText("You feel them slowly " + verb + ".  You now have [hips].");
						changed = true;
					break;

				case "butt":
					outputText("You wiggle around in your gown, the pleasant feeling of flower petals rubbing against your skin washes over you.  The feeling settles on your [butt].\n");
					if (player.butt.rating < idealButt) {
						verb = "enlarge";
						player.butt.rating++;
					} else {
						verb = "shrink";
						player.butt.rating--;
					}
					outputText("You feel it slowly " + verb + ". You now have a [butt].");
					changed = true;
					break;

				case "cock":
					outputText("Your [cock] feels strange as it brushes against the fabric of your gown.");
					(new BimboProgression).shrinkCock();
					changed = true;
					break;

				case "breasts":
					outputText("You feel like a beautiful flower in your gown.  Dawn approaches and you place your hands on your chest as if expecting them to bloom to greet the rising sun.\n");
					if (player.bRows() > 1) {
						player.removeBreastRow((player.bRows() - 1), 1);
						outputText("Some of your breasts shrink back into your body, leaving you with just " + num2Text(player.bRows()) + " rows.\n");
					}
					if (player.breastRows[0].breastRating < idealBreasts) {
						player.breastRows[0].breastRating++;
						outputText("Heat builds in your chest, and " + (player.breastRows[0].breastRating == 1 ? "it starts to swell" : "your boobs become bigger") + ".\n\nYou now have [breastcup] [breasts].");
					}
					else if (player.breastRows[0].breastRating > idealBreasts) {
						player.breastRows[0].breastRating--;
						outputText("Your chest feels lighter as your boobs shrink.\n\nYou now have [breastcup] [breasts].");
					}
					changed = true;
					break;

				case "girlyness":
					text = player.modFem(idealFem, 2);
					if (text == "") break;
					outputText("You run your [hands] across the fabric of your gown, then against your face as it feels like there is something you need to wipe off.\n");
					outputText(text);
					changed = true;
					break;

				default:
			}
			if (!changed) {   //if no small changes, start big changes
				outputText("\n\n");
				DryadProg();
			}
		}

		public function DryadProg():void {

		//types of changes
			var tfChoice:String = randomChoice("skin", "ears", "face", "lowerbody", "arms", "hair");
			switch (tfChoice) {
				case "ears":
					if (player.ears.type !== Ears.ELFIN) {
						outputText("There is a tingling on the sides of your head as your ears change to pointed elfin ears.");
						player.ears.type = Ears.ELFIN;
					}
					break;

				case "skin":
					if (player.skin.type !== Skin.PLAIN && player.skin.type !== Skin.BARK) {
						outputText("A tingling runs up along your [skin] as it changes back to normal");
						player.skin.restore();
					} else if ((player.skin.desc !== "bark" || player.skin.type !== Skin.BARK) && player.skin.type == Skin.PLAIN) {
						outputText("Your skin hardens and becomes the consistency of tree bark.");
						player.skin.setProps({
							type: Skin.BARK,
							adj: "rough",
							tone: "brown",
							desc: "bark"
						});
					}
					break;

				case "lowerbody":
					if (player.lowerBody.type !== LowerBody.HUMAN) {
						outputText("There is a rumbling in your lower body as it returns to a human shape.");
						player.lowerBody.type = LowerBody.HUMAN;
					}
					break;

				case "arms":
					if (player.arms.type !== Arms.HUMAN || player.arms.claws.type !== Claws.NORMAL) {
						outputText("Your hands shake and shudder as they slowly transform back into normal human hands.");
						player.arms.restore();
					}
					break;

				case "face":
					if (player.face.type !== Face.HUMAN) {
						outputText("Your face twitches a few times and slowly morphs itself back to a normal human face.");
						player.face.type = Face.HUMAN;
					}
					break;

				case "hair":
					if (player.hair.type !== Hair.LEAF) {
						outputText("Much to your shock, your hair begins falling out in tufts onto the ground. "
								  +" Moments later, your scalp sprouts vines all about that extend down and bloom into leafy hair.");
						player.hair.type = Hair.LEAF;
					}
					break;
				default:
			}
		}
	}
}


code:
/**
 * Created by aimozg on 15.01.14.
 */
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.PerkLib;
	import classes.Player;

	public final class InquisitorsCorset extends Armor {

		public function InquisitorsCorset() {
			super("I.Corst", "I.Corst", "inquisitor's corset", "an inquisitor's corset", 4, 2000, "This sexualized and feminine red and gold ensemble carries with it the hopes of a shamed sorcerer.  Wearing it will cause spells to tax your health instead of exhausting you.", "Light", false, false);
			boostsSeduction(10);
		}

		override public function useText():void {
			outputText("You take out the clothing you received from the underground chamber in the swamp.  The sexual nature of the clothing excites you a bit, as does the knowledge that it will be functional in combat.  You quickly disrobe, eager to try it on.\n\n");

			outputText("Checking to see whether the posture collar can be detached from the sleeves, you find a complete lack of any way to do so.  Shrugging, you slide your arms into the sleeves, sticking your middle fingers through the extended ends.  Golden embroidery down their length contains some of the most ornate and stylized pictures of dicks you have ever seen, culminating in an excessive amount of gold thread splayed in your palm, symbolizing the ejaculate.  You lift your chin to fit the posture collar in place, completely hiding your neck from view as you lace it from behind.  The dark red works nicely with your " + player.skin.tone + " " + player.skin.desc + ".   A small amount of delight fills you as you realize the collar is not as unforgiving as a true posture collar, allowing you a comfortable amount of movement - though you do briefly wonder what a fight would be like if it didn't.\n\n");

			outputText("You fit the corset on next, wrapping it around your waist and chest, hiding your " + player.nippleDescript(0) + "s beneath more red and gold trim.  As you lace the corset up you realize that what you had taken for a stylized sword rising up between the cups bears a much greater resemblance to a prick.  Fair enough.  The belt practically attaches to the corset as though it were made to be a single article of clothing, clasping beneath a set of heavily stylized golden lines that you suspect are meant to be a face in the middle of either prayer or oral sex, or possibly both.\n\n");

			outputText("Earlier suspicions about the skirt prove correct - it does not conceal in the slightest.  It covers some skin to the right side, mostly in the back, but your front is on full display to the world.  The skirt feels as though it should go on a dancing showgirl rather than an inquisitor, but you made the choice you did and the results are arousing.  Golden trim takes on the form of waving and twisting tentacles as the bottom of the skirt gets closer, looking as though it wants to burst from the fabric and molest its wearer.\n\n");

			//[(if PC has human, demon, or bee feet)
			if (player.isBiped()) outputText("Finally you slide your legs into the boots.  The heel itself is hollow, to accommodate any natural spurs on the wearer's foot, and the rest of the boot seems surprisingly fitted to your dimensions.  To a certain extent it feels as though it is reshaping itself as you enter - parts that initially feel tight loosen up in minutes, as if the boots were breaking themselves in.  If what the note said is true, and the armor adapts to he who finds it, perhaps even hooves and paws could have fit, given enough magical power used in the creation.  Laces run up the side of each boot all the way to your thighs, resembling the corset they were paired with.  The front of them bear golden symbology, akin to the symbols  that sat on the front of the secret chamber.  Based on your previous decoding, they're halfway between a prayer and an exaltation of cock.  Standing up in them, you smile as your " + player.buttDescript() + " rises with their influence.");
			///(else if PC has funny feet)
			else outputText("The final bit of the outfit is a pair of long-heeled lace-up boots, which, though decorated with gorgeous golden symbols spelling out what appears to be a hymn to sex, seem... relatively unusable in your current state.  You tuck them away someplace safe in case you ever become a biped again, then stand to your full height and assess yourself.");
			outputText("\n\n");

			outputText("You feel sexy... and pious.\n\n(Perk Gained - Blood Mage: Spells consume HP (minimum 5) instead of fatigue!)\n\n");
			//+lust
			dynStats("lus", 5);
		}

		override public function get description():String {
			var desc:String = super.description;
			desc += "\nSpecial: Blood Mage";
			return desc;
		}

		override public function playerEquip():Armor {
			while (player.findPerk(PerkLib.BloodMage) >= 0) player.removePerk(PerkLib.BloodMage);
			player.createPerk(PerkLib.BloodMage,0,0,0,0);
			return super.playerEquip();
		}

		override public function playerRemove():Armor {
			while (player.findPerk(PerkLib.BloodMage) >= 0) player.removePerk(PerkLib.BloodMage);
			return super.playerRemove();
		}
	}
}


code:
/**
 * Created by aimozg on 15.01.14.
 */
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.PerkLib;
	import classes.Player;

	public final class InquisitorsRobes extends ArmorWithPerk {

		public function InquisitorsRobes() {
			super("I.Robes", "I.Robes", "inquisitor's robes", "inquisitor's robes", 8, 2000, "These foreboding red and gold robes are embroidered with the symbols of a lost kingdom.  Wearing them will cause spells to tax your health instead of exhausting you.", "Light", PerkLib.BloodMage, 0, 0, 0, 0);
		}

		override public function useText():void {
			outputText("You unfold the robes you received from the secret chamber in the swamp and inspect them.  They have not changed since the last time you saw them - perhaps the transformative magic promised in the letter has been exhausted.  Looking at the two separate parts to the outfit, it becomes clear that the mantle is constructed of a thicker fabric and is intended to be the primary protection of the outfit - what protection a robe can provide, at least.  The undershirt is made of a much lighter material, and you dare say that it could prove quite a classy number on its own.  You strip naked and then slip into the robe.\n\n");

			outputText("The degree to which it fits you is moderately surprising.  For lack of a better word, it seems to be perfect.  The fabric does not cling to you, but gives you a full range of movement.  There is a clasp over the high collar, displaying a golden sword.  Though your arms are bare the holes through which your arms extend are comfortable, and have the same golden trim as the collar.  Along the middle of the robe the trim gathers around the waist, descending down the skirt in two lines.  As it reaches the bottom it explodes into elaborate embroidery circling around the back, patterning based on holy symbols and iconography that may have meant something long ago before the advent of demons.  Between the two lines of gold a sword is displayed, similar to the one on the collar's clasp.  You take a few dramatic movements to see how it responds, and find that you continue to enjoy free movement.\n\n");

			outputText("Taking the heavier coat, you slide your hands into the sleeves, and secure the belt firmly around your waist.  Your initial concern was that the sleeves would be too open, but in making a few quick motions with your hands you don't feel that the cloth gets in the way.  The weight of the gold-trimmed hood surprises you somewhat, but you quickly grow accustomed.  After attempting to move the hood down you realize that doing so is remarkably difficult; it's designed by clever stitching and wires to stay up, and straight.  You suppose that unless you're overheating there's no real need to adjust it.  The coat covers the undershirt's waist decorations, hiding them completely behind its belt.  Now-familiar sword imagery runs over your back, along your spine.  The loops of the belt meet twice - once behind your back, and once beneath the clasp.\n\n");

			outputText("To finish the look, you take the two fingerless alchemical gloves and slide them over your hands.  What seems to be a prayer is embroidered in gold on their back.\n\n");

			outputText("You feel pious.\n\n(<b>Perk Gained - Blood Mage</b>: Spells consume HP (minimum 5) instead of fatigue!)\n\n");
		}

		override public function get description():String {
			var desc:String = super.description;
			desc += "\nSpecial: Blood Mage";
			return desc;
		}

	}
}


code:
/**
 * Created by aimozg on 18.01.14.
 */
package classes.Items.Armors
{
	import classes.ItemType;
	import classes.Items.Armor;
	import classes.Player;

	public class LeatherArmorSegments extends Armor {

		public function LeatherArmorSegments() {
			super("UrtaLta", "UrtaLta", "leather armor segments", "leather armor segments", 5, 76, null, "Light", true);
		}
		override public function removeText():void {
			outputText("You have your old set of " + game.armors.LEATHRA.longName + " left over.  ");
		}

		override public function playerRemove():Armor {
			super.playerRemove();
			return game.armors.LEATHRA;
		}
	}
}


code:
package classes.Items.Armors
{
	import classes.Items.Armor;
	import classes.Items.UndergarmentLib;
	import classes.Player;

	public class LethiciteArmor extends Armor
	{
		public function LethiciteArmor()
		{
			super("LthcArm","Lthc. Armor","lethicite armor","a suit of glowing purple lethicite armor",28,3000,"This is a suit of lethicite armor. It's all purple and it seems to glow. The pauldrons are spiky to give this armor an imposing appearance. It doesn't seem to cover your crotch and nipples though. It appears to be enchanted to never break and you highly doubt the demons will be able to eat it!","Heavy");
		}

		override public function get def():Number { return 20 + int(player.cor / 10); }

		override public function useText():void
		{
			outputText("You " + player.clothedOrNaked("strip yourself naked before you ") + "proceed to put on the strange, purple crystalline armor. ");
			if (player.cor < 33) outputText("You hesitate at how the armor will expose your groin but you proceed to put it on anyway. ");
			if (player.cor >= 33 && player.cor < 66) outputText("You are not sure about the crotch-exposing armor. ");
			if (player.cor >= 66) outputText("You are eager to show off once you get yourself suited up. ");
			//Put on breastplate
			outputText("\n\nFirst, you clamber into the breastplate. It has imposing, spiked pauldrons to protect your shoulders. The breastplate shifts to accommodate your [chest] and when you look down, your [nipples] are exposed. ");
			if (player.biggestLactation() >= 4) outputText("A bit of milk gradually flows over your breastplate. ");
			//Put on leggings
			if (player.isBiped()) {
				outputText("\n\nNext, you slip into the leggings. By the time you get the leggings fully adjusted, you realize that the intricately-designed opening gives access to your groin! ");
				if (player.hasCock() && player.lowerGarment == UndergarmentLib.NOTHING) outputText("Your " + player.multiCockDescriptLight() + " hang" + (player.cocks.length == 1 ? "s" : "") + " freely. ");
				if (player.cor < 33) { //Low corruption
					if (player.lowerGarment != UndergarmentLib.NOTHING) outputText("Good thing you have your " + player.lowerGarment + " on!");
					else outputText("You blush with embarrassment. ");
				}
				else if (player.cor >= 33 && player.cor < 66) { //Medium corruption
					if (player.lowerGarment != UndergarmentLib.NOTHING) outputText("You are unsure about whether you should keep your " + player.lowerGarment + " on or not.");
					else outputText("You are unsure how you feel about your crotch being exposed to the world.");
				}
				else if (player.cor >= 66) { //High corruption
					if (player.lowerGarment != UndergarmentLib.NOTHING) outputText("You ponder over taking off your undergarments.");
					else outputText("You delight in having your nether regions open to the world.");
				}
				outputText(" Then, you slip your feet into the 'boots'; they aren't even covering your feet. You presume they were originally designed for demons, considering how the demons either have high-heels or clawed feet.");
			}
			else {
				outputText("\n\nThe leggings are designed for someone with two legs so you leave them in your [inv].");
			}
			//Finishing touches
			outputText("\n\nFinally, you put the bracers on to protect your arms. Your fingers are still exposed so you can still get a good grip.");
			outputText("\n\nYou are ready to set off on your adventures!\n\n");
		}
	}

}