code:
package classes.internals
{
	/**
	 * ...
	 * @author ...
	 */
	public class ButtonData
	{
		public var text:String;
		public var callback:Function;
		public var toolTipText:String;
		public var toolTipHeader:String;
		public var arg1:*;
		public var arg2:*;
		public var arg3:*;
		public var disabled:Boolean;
		public var color:Array;

		public function ButtonData(text:String,callback:Function,arg1:* = -9000, arg2:* = -9000, arg3:* = -9000,toolTipText:String="",toolTipHeader:String="",disabled:Boolean = false, color:Array = null)
		{
			this.text = text;
			this.callback = callback;
			this.toolTipText = toolTipText;
			this.toolTipHeader = toolTipHeader;
			this.arg1 = arg1;
			this.arg2 = arg2;
			this.arg3 = arg3;
			this.disabled = disabled;
			this.color = color;
		}

	}

}


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

	/**
	 * Class for performing chained random actions (function/method calls) derived from ChainedDrop by aimozg
	 * @since May 7, 2017
	 * @author Stadler76
	 */
	public class ChainedAction implements RandomAction
	{
		private var actions:Array = [];
		private var probs:Array = [];
		private var defaultAction:Function;

		public function ChainedAction(defaultAction:Function = null)
		{
			this.defaultAction = defaultAction;
		}

		public function add(action:Function, prob:Number):ChainedAction
		{
			if (prob < 0 || prob > 1) {
				CoC_Settings.error("Invalid probability value " + prob);
			}
			actions.push(action);
			probs.push(prob);
			return this;
		}

		public function elseAction(action:Function):ChainedAction
		{
			this.defaultAction = action;
			return this;
		}

		public function exec():void
		{
			for (var i:int = 0; i < actions.length; i++) {
				if (Math.random() < probs[i]) {
					actions[i]();
					return;
				}
			}

			if (defaultAction != null)
				defaultAction();
		}
	}
}

license: unknown


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

	/**
	 * Class for returning chained random choices derived from ChainedDrop by aimozg
	 * @since March 7, 2018
	 * @author Stadler76
	 */
	public class ChainedChoice implements RandomChoice
	{
		private var choices:Array = [];
		private var probs:Array = [];
		private var defaultChoice:*;

		public function ChainedChoice(defaultChoice:* = null)
		{
			this.defaultChoice = defaultChoice;
		}

		public function add(item:*, prob:Number):ChainedChoice
		{
			if (prob < 0 || prob > 1) {
				CoC_Settings.error("Invalid probability value "+prob);
			}
			choices.push(item);
			probs.push(prob);
			return this;
		}

		public function elseChoice(item:*):ChainedChoice
		{
			this.defaultChoice = item;
			return this;
		}

		public function choose():*
		{
			for (var i:int = 0; i < choices.length; i++) {
				if (Math.random() < probs[i]) {
					return choices[i];
				}
			}

			return defaultChoice;
		}
	}
}


code:
/**
 * Created by aimozg on 11.01.14.
 */
package classes.internals
{
	import classes.CoC_Settings;

	public class ChainedDrop implements RandomDrop
	{
		private var items:Array = [];
		private var probs:Array = [];
		private var defaultItem:*;
		public function ChainedDrop(defaultItem:* = null)
		{
			this.defaultItem = defaultItem;
		}
		public function add(item:*,prob:Number):ChainedDrop{
			if (prob<0 || prob>1){
				CoC_Settings.error("Invalid probability value "+prob);
			}
			items.push(item);
			probs.push(prob);
			return this;
		}
		public function elseDrop(item:*):ChainedDrop{
			this.defaultItem = item;
			return this;
		}

		public function roll():*
		{
			for (var i:int = 0; i<items.length; i++){
				if (Math.random()<probs[i]) return items[i];
			}
			return defaultItem;
		}
	}
}


code:
/**
 * Created by aimozg on 02.04.2017.
 */
package classes.internals {
public class CounterGroup extends ArrayWithDefault {
	public function CounterGroup(array:Array) {
		super(array);
	}

	override protected function defaultValue():* {
		return 0;
	}
}
}


code:
/**
 * Created by aimozg on 27.03.2017.
 */
package classes.internals {
import classes.GlobalFlags.kCOUNTERS;

/**
 * A superclass for CountersStorage wrappers
 */
public class CountersAPI extends kCOUNTERS{
	public var _storage:CountersStorage;
	public function CountersAPI(_storage:CountersStorage) {
		this._storage = _storage;
	}
}
}


code:
/**
 * Created by aimozg on 27.03.2017.
 */
package classes.internals {
import classes.GlobalFlags.kCOUNTERS;

import flash.utils.Proxy;
import flash.utils.flash_proxy;

public class CountersStorage extends ArrayWithDefault {

	public function CountersStorage() {
		super();
	}

	override protected function cast(o:*):* {
		if (o is CounterGroup) return o;
		if (o is Array) return new CounterGroup(o);
		return defaultValue();
	}

	override protected function defaultValue():* {
		return new CounterGroup([]);
	}
}
}


code:
package classes.internals
{
	import coc.view.CoCButton;
	/**
	 * Using 'Extract interface' to use GUI functions without having to drag the CoC class, and with it,
	 * the entire fucking game, into a unit test.
	 */
	public interface GuiInput
	{
		function addButton(pos:int, text:String = "", func1:Function = null, arg1:* = -9000, arg2:* = -9000, arg3:* = -9000, toolTipText:String = "", toolTipHeader:String = ""):CoCButton;

		function menu():void;
	}
}


code:
package classes.internals
{

	/**
	 * Minimal interface to allow output to the GUI. This interface is used to break the dependencies that would
	 * get dragged in when using the Output class directly.
	 */
	public interface GuiOutput
	{
		function text(text:String):GuiOutput;

		function flush():void;

		function header(headLine:String):GuiOutput;

		function clear(hideMenuButtons:Boolean = false):GuiOutput;
	}
}


code:
package classes.internals
{
	import flash.errors.IllegalOperationError;
	import flash.utils.getQualifiedClassName;
	import mx.logging.Log;
	import mx.logging.ILogger;

	/**
	 * Factory to create loggers for classes.
	 */
	public class LoggerFactory
	{
		/**
		 * Symbols that cannot be used in a category name
		 */
		public static const ILLEGAL_SYMBOLS:String = "[]~$^&\/(){}<>+=`!#%?,:;'\"@";

		private static const PACKAGE_DELIMITER:RegExp = /::/g;
		private static const PACKAGE_DELIMITER_REPLACEMENT:String = ".";

		public function LoggerFactory()
		{
			throw new IllegalOperationError("This class cannot be instantiated.");
		}

		/**
		 * Create a logger for the given class. Loggers are cached by mx.logging.Log, so using the same Class
		 * multiple times will return the same logger instance.
		 * @param	clazz to create a logger for
		 * @return a new logger for the class
		 */
		public static function getLogger(clazz:Class):ILogger {
			var sanitizedFQN:String = getQualifiedClassName(clazz).replace(PACKAGE_DELIMITER, PACKAGE_DELIMITER_REPLACEMENT);
			return Log.getLogger(sanitizedFQN);
		}
	}
}


code:
package classes.internals
{
	import classes.BaseContent;
	import classes.Creature;
	import classes.MonsterAbilities;
	import classes.StatusEffects;
	import classes.PerkLib;
	import classes.Scenes.Combat.CombatAttackData;

	public class MonsterAI extends BaseContent implements RandomAction
	{
		private var abilities:MonsterAbilities = new MonsterAbilities();
		private var availableActions:Array = [];
		private var allActions:Array = [];
		private var rangedAmount:int = 0;
		private var meleeAmount:int = 0;
		private var flyingAmount:int = 0;
		private var waitWeight:int  = 0;
		private var sum:Number = 0;
		private const MELEE:int = 0;
		private const RANGED:int = 1;
		//private const NONE:int = 2;
		private const SELF:int = 2;

		public function get RANGE_MELEE():int { return CombatAttackData.RANGE_MELEE;  }
		public function get RANGE_RANGED():int { return CombatAttackData.RANGE_RANGED;  }
		///Targets self.
		public function get RANGE_SELF():int { return CombatAttackData.RANGE_SELF;  }
		///Tease. Ranged, but it isn't necessarily an attack.
		public function get RANGE_TEASE():int { return CombatAttackData.RANGE_TEASE;  }
		///Can't be avoided.
		public function get RANGE_OMNI():int { return CombatAttackData.RANGE_OMNI;  }
		///Melee, hits flying and distant enemies
		public function get RANGE_MELEE_FLYING():int { return CombatAttackData.RANGE_MELEE_FLYING;  }
		///Melee, hits distant enemies but not flying ones. Removes distance.
		public function get RANGE_MELEE_CHARGING():int { return CombatAttackData.RANGE_MELEE_CHARGING;  }

		//Different distances.
		public function get DISTANCE_MELEE():int { return CombatAttackData.DISTANCE_MELEE;  }
		public function get DISTANCE_DISTANT():int { return CombatAttackData.DISTANCE_DISTANT;  }

		//Fatigue types.
		public function get FATIGUE_NONE():int { return CombatAttackData.FATIGUE_NONE;  }
		public function get FATIGUE_MAGICAL():int { return CombatAttackData.FATIGUE_MAGICAL;  }
		public function get FATIGUE_PHYSICAL():int { return CombatAttackData.FATIGUE_PHYSICAL;  }
		public function get FATIGUE_MAGICAL_HEAL():int { return CombatAttackData.FATIGUE_MAGICAL_HEAL;  }

		public function MonsterAI(first:Function = null, firstWeight:Number = 0, when:Boolean = true, cost:Number = 0, typeFatigue:int = 0,type:int = 0)
		{
			if (first != null && canExecute(when,cost,typeFatigue,type)) {
				availableActions.push([first, firstWeight, when, cost, typeFatigue, type]);
				updateAbilityAmounts(type,firstWeight);
            }else{
                if(!monster.hasFatigue(cost,typeFatigue)) waitWeight++;
            }
		}

		public function updateAbilityAmounts(id:int,weight:Number):void{
			sum += weight;
			if (combatAttackData.isRanged(id) || combatAttackData.ignoreRange(id)) rangedAmount++;
			if (combatAttackData.isMeleeOnly(id)) meleeAmount++;
			if (combatAttackData.isFlying(id)) flyingAmount++;
		}

		public function canExecute(when:Boolean = true, cost:Number = 0,  typeFatigue:int = 0,type:int = 0):Boolean{

			return when && monster.hasFatigue(cost, typeFatigue) && combatAttackData.canReach(monster,player,monster.distance,type);
		}

		public function add(action:Function, weight:Number = 1, when:Boolean = true, cost:Number = 0,  typeFatigue:int = 0,type:int = 0):MonsterAI
		{
			if (canExecute(when,cost,typeFatigue,type)){
				availableActions.push([action, weight,when,cost,typeFatigue,type]);
				updateAbilityAmounts(type,weight);
			}else{
				if(when && !monster.hasFatigue(cost,typeFatigue)) waitWeight++;
			}
			return this;
		}

		public function exec():void
		{
			sum = Math.max(1,sum);//make sure we don't get a 0 weight. That screws things up.
			monster.prefersRanged = false;
			if (waitWeight/availableActions.length > 0.3 && monster.fatigue >= monster.maxFatigue()*0.85) add(abilities.wait,sum/3,true,0,monster.FATIGUE_NONE,monster.RANGE_SELF);
			if (rangedAmount/availableActions.length >= 0.3) monster.prefersRanged = true;

			//To stop annoyances, enemies shouldn't attempt to distance themselves unless they're in a tactical disadvantage. They should still attempt to close the distance, though.
			if (monster.shouldMove(DISTANCE_DISTANT) && monster.distance == DISTANCE_MELEE && monster.canMove()) add(abilities.distanceSelf, sum / 5, true, 15, monster.FATIGUE_PHYSICAL, monster.RANGE_SELF);
			if (monster.shouldMove(DISTANCE_MELEE,true)&& monster.distance == DISTANCE_DISTANT && monster.canMove()) add(abilities.approach, sum / 5, true, 15, monster.FATIGUE_PHYSICAL, monster.RANGE_SELF);
			if (availableActions.length == 0){//If there's no available action(due to fatigue or silences) then just attack. Placeholder for now. In the future I want to give monsters the ability to wait to regain stamina, or even run away.
				if (canExecute(true, 0, 0, monster.getRegularAttackRange())) monster.eAttack();
				else add(abilities.wait, 1, true, 0, 0, RANGE_SELF);
				return;
			}
			/*if (availableActions.length == 0){//If there's no available action(due to fatigue or silences) then just attack. Placeholder for now. In the future I want to give monsters the ability to wait to regain stamina, or even run away.
				monster.eAttack();
				return;
			}*/
			var random:Number = Math.random()*sum;
			var action:Function = null;
			var cost:Number = 0;
			var typeFatigue:Number = 2;
			var type:Number = 0;
			while (random > 0 && availableActions.length > 0) {
				var pair:Array = availableActions.shift();//not a pair anymore shhh
					action = pair[0]
					random -= pair[1];
					cost = pair[3];
					typeFatigue = pair[4];
					type = pair[5];
			}
			monster.changeFatigue(cost, typeFatigue);
			if (action != null)
				action();
			if (type == RANGE_MELEE_CHARGING) combatAttackData.closeDistance(monster);
		}

		public function clone():MonsterAI
		{
			var other:MonsterAI = new MonsterAI();
			other.availableActions = availableActions.slice();
			other.sum = sum;
			return other;
		}

		public var spellCostCharge:int = 10;
		public var spellCostBlind:int = 8;
		public var spellCostWhitefire:int = 15;
		public var spellCostArouse:int = 10;
		public var spellCostHeal:int = 15;
		public var spellCostMight:int = 10;

		public function addWhiteMagic():void{
			addWhitefire();
			addBlind();
			addChargeweapon();
		}

		public function addBlackMagic():void{
			addArouse();
			addHeal();
			addMight();
		}

		public function addWhitefire():void{
			add(abilities.whitefire, 1, monster.lust < 50, spellCostWhitefire, monster.FATIGUE_MAGICAL, monster.RANGE_RANGED);
		}

		public function addBlind():void{
			add(abilities.blind, 1, monster.lust < 50 && !player.hasStatusEffect(StatusEffects.Blind), spellCostBlind, monster.FATIGUE_MAGICAL, monster.RANGE_RANGED);
		}

		public function addArouse():void{
			add(abilities.arouse, 1, monster.lust < 50, spellCostArouse, monster.FATIGUE_MAGICAL, monster.RANGE_RANGED);
		}

		public function addChargeweapon():void{
			add(abilities.chargeweapon, 1, monster.lust < 50, spellCostCharge, monster.FATIGUE_MAGICAL, monster.RANGE_SELF);
		}

		public function addHeal():void{
			add(abilities.heal, 1, monster.lust > 60, spellCostHeal, monster.FATIGUE_MAGICAL_HEAL, monster.RANGE_SELF);
		}

		public function addMight():void{
			add(abilities.might, 1, monster.lust > 50, spellCostMight, monster.FATIGUE_MAGICAL, monster.RANGE_SELF);
		}
	}
}


code:
/**
 * Created by aimozg on 27.03.2017.
 */
package classes.internals {
import classes.GlobalFlags.kCOUNTERS;
import classes.GlobalFlags.kGAMECLASS;

public class MonsterCounters extends kCOUNTERS{
	public function get encountered():int { return storage[index][_MONSTER_ENCOUNTERED]||0}
	public function set encountered(value:int): void {
		setValue(_MONSTER_ENCOUNTERED,value);
	}
	public function get battled():int { return storage[index][_MONSTER_BATTLED]||0}
	public function set battled(value:int): void {
		setValue(_MONSTER_BATTLED, value);
	}
	public function get won_total():int { return storage[index][_MONSTER_WON_TOTAL]||0}
	public function set won_total(value:int): void {
		setValue(_MONSTER_WON_TOTAL, value);
	}
	public function get won_lust():int { return storage[index][_MONSTER_WON_LUST]||0}
	public function set won_lust(value:int): void {
		setValue(_MONSTER_WON_LUST, value);
	}
	public function get won_hp():int { return storage[index][_MONSTER_WON_HP]||0}
	public function set won_hp(value:int): void {
		setValue(_MONSTER_WON_HP, value);
	}
	public function get lost_total():int { return storage[index][_MONSTER_LOST_TOTAL]||0}
	public function set lost_total(value:int): void {
		setValue(_MONSTER_LOST_TOTAL, value);
	}
	public function get lost_lust():int { return storage[index][_MONSTER_LOST_LUST]||0}
	public function set lost_lust(value:int): void {
		setValue(_MONSTER_LOST_LUST, value);
	}
	public function get lost_hp():int { return storage[index][_MONSTER_LOST_HP]||0}
	public function set lost_hp(value:int): void {
		setValue(_MONSTER_LOST_HP, value);
	}
	public function get ranfrom():int { return storage[index][_MONSTER_RANFROM]||0}
	public function set ranfrom(value:int): void {
		setValue(_MONSTER_RANFROM, value);
	}
	public function get sex_total():int { return storage[index][_MONSTER_SEX_TOTAL]||0}
	public function set sex_total(value:int): void {
		setValue(_MONSTER_SEX_TOTAL, value);
	}
	public function get sex_when_won():int { return storage[index][_MONSTER_SEX_WHEN_WON] || 0}
	public function set sex_when_won(value:int): void {
		setValue(_MONSTER_SEX_WHEN_WON, value);
	}
	public function get sex_when_lost():int { return storage[index][_MONSTER_SEX_WHEN_LOST] || 0}
	public function set sex_when_lost(value:int): void {
		setValue(_MONSTER_SEX_WHEN_LOST, value);
	}
	public function get sex_nobattle():int { return storage[index][_MONSTER_SEX_NO_BATTLE] || 0}
	public function set sex_nobattle(value:int): void {
		setValue(_MONSTER_SEX_NO_BATTLE, value);
	}

	public function setValue(subindex:int,value:int):void {
		modValue(subindex,value - storage[index][subindex]);
	}
	public function modValue(subindex:int,delta:int):void {
		storage[index][subindex] += delta;
		if (group != null) group.modValue(subindex,delta);
	}
	private function get storage():CountersStorage {
		return kGAMECLASS.counters._storage;
	}
	public function get group():MonsterCounters {
		if (_group_index<0) return null;
		return Library[_group_index];
	}
	public function get group_index():int {
		return _group_index;
	}

	private var index:int;
	private var _group_index:int;
	public function MonsterCounters(index:int,group:int) {
		this.index = index;
		this._group_index = group;
		Library[index] = this;
	}
	public static const Library:Object = {}; // index:int -> MonsterObject
}
}


code:
package classes.internals
{
import classes.PregnancyStore;
import classes.internals.GuiOutput;
	import classes.Player;
	import flash.errors.IllegalOperationError;

	/**
	 * Utility methods related to pregnancy.
	 */
	public class PregnancyUtils
	{
		public function PregnancyUtils()
		{
			throw new IllegalOperationError("Cannot create instance of a Util class");
		}

		/**
		 * Check if the player has a vagina and create one if missing.
		 * This is usually used when a pregnant player is giving birth,
		 * as the scene text would be inconsistent and any operations on a
		 * non-existent vagina would crash the game.
		 */
		public static function createVaginaIfMissing(guiForOutput:GuiOutput, player:Player): void {
			if (player.vaginas.length === 0) {
				guiForOutput.text("\nYou feel a terrible pressure in your groin... then an incredible pain accompanied by the rending of flesh.  <b>You look down and behold a new vagina</b>.\n");
				player.createVagina();
			}
		}

        public static function isMouseCum(type:int):Boolean{
            return [PregnancyStore.PREGNANCY_MOUSE,PregnancyStore.PREGNANCY_AMILY,PregnancyStore.PREGNANCY_JOJO].indexOf(type) >= 0;
        }
	}
}


code:
/**
 * Created by aimozg on 13.05.2017.
 */
package classes.internals {
import mx.logging.ILogger;

public class Profiling {
	function Profiling() {
	}

	private static const PF_LOGGER:ILogger        = LoggerFactory.getLogger(Profiling);
	private static var PF_DEPTH:int               = 0; // Callstack depth
	private static const PF_NAME:Array            = [];// Callstack method names
	private static const PF_START:Array           = [];// Callstack of Begin() times
	private static const PF_ARGS:Array            = [];// Callstack of method arguments
	private static const PF_COUNT:Object          = {};// method -> times called
	private static const PF_TIME:Object           = {};// method -> total execution time
	private static function shouldProfile(classname:String, methodName:String):Boolean {
		return true;
	}
	private static function shouldReportProfiling(classname:String, origMethodName:String, dt:Number, pfcount:int):Boolean {
		return dt > 100;
	}
	public static function LogProfilingReport():void {
		for (var key:String in PF_COUNT) {
			var s:String    = "[PROFILE] ";
			s += key;
			var pfcount:int = PF_COUNT[key];
			s += ", called " + pfcount + " times";
			var pftime:*    = PF_TIME[key];
			s += ", total time ";
			if (pftime > 10000) s += Math.floor(pftime / 1000) + "s";
			else s += pftime + "ms";
			if (pftime > 0 && pfcount > 0) {
				s += ", avg time " + (pftime / pfcount).toFixed(1) + "ms";
			}
			PF_LOGGER.info(s);
		}
	}
	public static function Begin(classname:String, methodName:String, ...rest:Array):void {
		if (!shouldProfile(classname, methodName)) return;
		methodName           = classname + "." + methodName;
		PF_NAME[PF_DEPTH]    = methodName;
		PF_START[PF_DEPTH]   = new Date().getTime();
		PF_ARGS[PF_DEPTH]    = rest;
		PF_COUNT[methodName] = (PF_COUNT[methodName] | 0) + 1;
		PF_DEPTH++;
	}
	public static function End(classname:String, methodName:String):void {
		if (!shouldProfile(classname, methodName)) return;
		var origMethodName:String = methodName;
		methodName                = classname + "." + methodName;
		var t1:Number             = new Date().getTime();
		PF_DEPTH--;
		while (PF_DEPTH >= 0 && PF_NAME[PF_DEPTH] != methodName) {
			PF_LOGGER.error("[ERROR] Inconsistent callstack, expected '" + methodName + "', got '" + PF_NAME[PF_DEPTH] + "'(" +
							PF_ARGS[PF_DEPTH].join() + ")");
			PF_DEPTH--;
		}
		if (PF_DEPTH < 0) {
			PF_LOGGER.error("[ERROR] Empty callstack, expected '" + methodName + "'");
			PF_DEPTH = 0;
			return;
		}
		var dt:Number       = t1 - PF_START[PF_DEPTH];
		PF_TIME[methodName] = (PF_TIME[methodName] | 0) + dt;
		var pfcount:int     = PF_COUNT[methodName];
		var args:Array      = PF_ARGS[PF_DEPTH];
		if (shouldReportProfiling(classname, origMethodName, dt, pfcount)) {
			var s:String = "[PROFILE] ";
			for (var i:int = PF_DEPTH; i-- > 0;) s += "  ";
			s += methodName;
			if (args.length > 0) s += "(" + args.join(", ") + ")";
			s += " " + dt + "ms";
			if (pfcount > 1) {
				s += ", called " + pfcount + " times";
				var pftime:* = PF_TIME[methodName];
				if (pftime > 0) {
					s += ", total time ";
					if (pftime > 10000) s += Math.floor(pftime / 1000) + "s";
					else s += pftime + "ms";
					s += ", avg time " + (pftime / pfcount).toFixed(1) + "ms";
				}
			}
			PF_LOGGER.info(s);
		}
	}
}
}


code:
package classes.internals
{
	/**
	 * Interface for performing random actions (function/method calls) derived from RandomDrop by aimozg
	 * @since May 7, 2017
	 * @author Stadler76
	 */
	public interface RandomAction
	{
		function exec():void;
	}
}


code:
package classes.internals
{
	/**
	 * Interface for returning random choices derived from RandomDrop by aimozg
	 * @since March 7, 2018
	 * @author Stadler76
	 */
	public interface RandomChoice
	{
		function choose():*;
	}
}


code:
/**
 * Created by aimozg on 11.01.14.
 */
package classes.internals
{
	public interface RandomDrop
	{
		function roll():*;
	}
}


code:
package classes.internals
{

	/**
	 * Interface that provides methods for getting random numbers.
	 */
	public interface RandomNumberGenerator
	{
		/**
		 * Returns a number that is between 0 and max - 1 inclusive.
		 * @param	max the upper limit for the random number
		 * @return a value between 0 and max - 1
		 */
		function random(max:int):int;

		/**
		 * Returns a number that is between 0 and max inclusive.
		 * @param	max the upper limit for the random number
		 * @return a value between 0 and max inclusive
		 */
		function randomCorrected(max:int):int;
	}
}


code:
/**
 * Created by aimozg on 27.03.2017.
 */
package classes.internals {
import classes.internals.MonsterCounters;
import classes.internals.MonsterCounters;
import classes.internals.MonsterCounters;

public class RootCounters extends CountersAPI {
	public function RootCounters(_storage:CountersStorage) {
		super(_storage);
	}
	public const mCumWitch:MonsterCounters = new MonsterCounters(MONSTER_CUMWITCH,MONGROUP_HUMAN);
	public const mGoblin:MonsterCounters = new MonsterCounters(MONSTER_GOBLIN,MONGROUP_GOBLINOID);
	public const mGoblinAssassin:MonsterCounters = new MonsterCounters(MONSTER_GOBLINASSASSIN,MONGROUP_GOBLINOID);
	public const mGoblinElder:MonsterCounters = new MonsterCounters(MONSTER_GOBLINELDER,MONGROUP_GOBLINOID);
	public const mGoblinMatron:MonsterCounters = new MonsterCounters(MONSTER_GOBLINMATRON,MONGROUP_GOBLINOID);
	public const mGoblinShaman:MonsterCounters = new MonsterCounters(MONSTER_GOBLINSHAMAN,MONGROUP_GOBLINOID);
	public const mGoblinWarrior:MonsterCounters = new MonsterCounters(MONSTER_GOBLINWARRIOR,MONGROUP_GOBLINOID);
	public const mImp:MonsterCounters = new MonsterCounters(MONSTER_IMP,MONGROUP_DEMON);
	public const mImplord:MonsterCounters = new MonsterCounters(MONSTER_IMPLORD,MONGROUP_DEMON);
	public const mNaga:MonsterCounters = new MonsterCounters(MONSTER_NAGA,MONGROUP_REPTILIAN);
	public const mSandtrap:MonsterCounters = new MonsterCounters(MONSTER_SANDTRAP,MONGROUP_INSECT);
	public const mSandWitch:MonsterCounters = new MonsterCounters(MONSTER_SANDWITCH,MONGROUP_HUMAN);
	public const mTentacleBeast:MonsterCounters = new MonsterCounters(MONSTER_TENTACLEBEAST,-1);

	public const mgGoblinoids:MonsterCounters = new MonsterCounters(MONGROUP_GOBLINOID,-1);
}
}


code:
package classes.internals
{

	/**
	 * Interface for serialization and de-serialization.
	 * This is used to store class state in an object, so it can be persisted either
	 * to a shared object or file.
	 * The interface also provides a function to reverse the process.
	 */
	public interface Serializable
	{
		/**
		 * Serialize a class so it can be stored. Any state that is not serialized will be lost and replaced with the
		 * default value on deserialization.
		 * The class variables need to be stored manually.
		 * The object that is passed in must be initialized so class can write to it.
		 *
		 * e.g.:
		 * relativeRootObject.foo = intValue;
		 * relativeRootObject.bar = StringValue;
		 * relativeRootObject.baz = [];
		 * this.complexObject.serialize(relativeRootObject.baz);
		 *
		 * @param	relativeRootObject the object this class should write to
		 */
		function serialize(relativeRootObject:*):void;

		/**
		 * Deserialize a class, restoring it's state. Deserialization requires some form of default constructor, this can be achieved
		 * with all parameters having a default value.
		 *
		 * @param	relativeRootObject the object this class should read from
		 */
		function deserialize(relativeRootObject:*):void;

		/**
		 * Upgrade from an earlier version of the serialized data.
		 * This modifies the loaded object so it can be processed by the
		 * deserialization code.
		 * @param	relativeRootObject the loaded serialized data
		 * @param	serializedDataVersion a non-negative integer indicating the version of the loaded data
		 */
		function upgradeSerializationVersion(relativeRootObject:*, serializedDataVersion:int):void;

		/**
		 * Get the current serialization version for this class.
		 * @return the current serialization version
		 */
		function currentSerializationVerison():int;
	}
}


code:
package classes.internals
{
	import classes.Items.Armors.Nothing;
	import flash.errors.IllegalOperationError;
	import classes.internals.LoggerFactory;
	import mx.logging.ILogger;
	import classes.internals.Serializable;
	import ArgumentError;

	/**
	 * A class providing utility methods to make serialization and deserialization easier.
	 */
	public class SerializationUtils
	{
		private static const LOGGER:ILogger = LoggerFactory.getLogger(SerializationUtils);

		private static const SERIALIZATION_VERSION_PROPERTY:String = "serializationVersion";

		public function SerializationUtils()
		{
			throw new IllegalOperationError("This class cannot be instantiated");
		}

		/**
		 * Serializes a Vector into an array.
		 * @param	vector to serialize
		 * @return a array containing the serialized vector
		 */
		public static function serializeVector(vector:Vector.<*>):Array {
			var serialized:Array = [];

			for each(var element:Serializable in vector) {
				var obj:Array = [];
				serialized.push(obj);

				SerializationUtils.serialize(obj, element);
			}

			return serialized;
		}

		/**
		 * Deserializes a Array into a Vector of Serializable
		 * @param   destinationVector Vector where deserialized items will be written
		 * @param	serializedVector an Array containing the serialized vector
		 * @param	type of the serialized Vector
		 * @return a deserialized Vector
		 */
		public static function deserializeVector(destinationVector:Vector.<*>, serializedVector:Array, type:Class):void {
			// 'is' will only work on an instance
			if (!(new type() is Serializable)) {
				throw new ArgumentError("Type must implement Serializable");
			}

			if (destinationVector === null) {
				throw new ArgumentError("Destination Vector cannot be null");
			}

			if (serializedVector === null) {
				throw new ArgumentError("Serialized Vector cannot be null");
			}

			for each(var element:Object in serializedVector) {
				var instance:Serializable = new type();
				SerializationUtils.deserialize(element, instance);
				destinationVector.push(instance);
			}
		}

		/**
		 * Casts a vector from one type to another. DOES NO VALIDATION.
		 * @param	destinationVector vector where casted elements will be put
		 * @param	sourceVector where elements for casting will be read from
		 * @param	destinationType the class to cast to
		 */
		public static function castVector(destinationVector:*, sourceVector:*, destinationType:Class):void {
			/**
			 * If anyone has a better idea, i'm all ears.
			 * Implement your solution and see if the tests pass.
			 */

			for each(var element:* in sourceVector) {
				destinationVector.push(element as destinationType);
			}
		}

		/**
		 * Get the serialization version from the object, if any.
		 * @param	relativeRootObject that possibly contains a serialization version
		 * @return the serialization version, or 0 if no version is found
		 */
		public static function serializationVersion(relativeRootObject:*):int {
			return relativeRootObject[SERIALIZATION_VERSION_PROPERTY];
		}

		/**
		 * Check the version of the serialized data and compare it with the current version.
		 * @param	relativeRootObject object that contains serialized data
		 * @return true if the serialized version is compatible with the current verison
		 */
		public static function serializedVersionCheck(relativeRootObject:*, expectedVersion:int):Boolean {
			var version:int = SerializationUtils.serializationVersion(relativeRootObject);

			if (version > expectedVersion) {
				LOGGER.error("Serialized version is {0}, but the current version is {1}. Backward compatibility is not guaranteed!", version, expectedVersion);
				return false;
			}else{
				LOGGER.debug("Serialized version is {0}", version);
			}

			return true;
		}

		/**
		 * Check the version of the serialized data and compare it with the current version. Throws a Exception
		 * if the version is newer.
		 * @param	relativeRootObject object that contains serialized data
		 * @throws RangeError if the stored version is newer than the current version
		 */
		public static function serializedVersionCheckThrowError(relativeRootObject:*, expectedVersion:int):void {
			if (!SerializationUtils.serializedVersionCheck(relativeRootObject, expectedVersion)) {
				throw new RangeError("Stored version is newer than the current version");
			}
		}

		/**
		 * Deserialize a class. This method is intended to automate deserialization, in order to avoid
		 * a lot of code duplication.
		 * @param	relativeRootObject the object that contains the serialized classes data
		 * @param	serialized class instance that should have it's state restored
		 */
		public static function deserialize(relativeRootObject:*, serialized:Serializable):void {
			LOGGER.debug("Deserializing  {0}...", serialized);

			objectDefinedCheck(relativeRootObject, "Object passed for deserialization must be defined. Does the loaded property exist?")
			objectDefinedCheck(serialized, "Instance of class to load is not defined. Did you call the class constructor?");

			SerializationUtils.serializedVersionCheckThrowError(relativeRootObject, serialized.currentSerializationVerison());
			var serializedObjectVersion:int = SerializationUtils.serializationVersion(relativeRootObject);

			serialized.upgradeSerializationVersion(relativeRootObject, serializedObjectVersion);
			serialized.deserialize(relativeRootObject);
		}

		/**
		 * Serialize a class. This method is intended to automate serialization, in order to avoid
		 * a lot of code duplication.
		 *
		 * @param	relativeRootObject to write the classes data to
		 * @param	toSerialize instance of class to serialize
		 */
		public static function serialize(relativeRootObject:*, toSerialize:Serializable):void {
			LOGGER.debug("Serializing {0}...", toSerialize);

			objectDefinedCheck(relativeRootObject, "Object used for storage must be defined. Did you forget to initialize e.g. foo = []; ?");
			objectDefinedCheck(toSerialize, "Instance of class to store is not defined. Did you call the class constructor?");

			relativeRootObject[SERIALIZATION_VERSION_PROPERTY] = toSerialize.currentSerializationVerison();

			toSerialize.serialize(relativeRootObject);
		}

		private static function objectDefinedCheck(object:*, message:String):void {
			if (object === null || object === undefined) {
				LOGGER.error("Object failed defined check with message: {0}", message);
				throw new ArgumentError(message);
			}
		}
	}
}


code:
/**
 * Created by aimozg on 18.01.14.
 */
package classes.internals
{
	import classes.*;
	import coc.script.Eval;
	import classes.internals.LoggerFactory;

import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;

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

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

		private static const NUMBER_WORDS_NORMAL:Array		= ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
		private static const NUMBER_WORDS_CAPITAL:Array		= ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];
		private static const NUMBER_WORDS_POSITIONAL:Array	= ["zeroth", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"];

		/**
		 * Default RNG instance. Uses Utils.rand internally.
		 */
		public static const DEFAULT_RNG:RandomNumberGenerator = new ActionScriptRNG();

		public function Utils()
		{
		}

		// curryFunction(f,args1)(args2)=f(args1.concat(args2))
		// e.g. curryFunction(f,x,y)(z,w) = f(x,y,z,w)
		public static function curry(func:Function,...args):Function
		{
			if (func == null) CoC_Settings.error("carryFunction(null,"+args+")");
			return function (...args2):*{
				return func.apply(null,args.concat(args2));
			};
		}
		public static function bindThis(func:Function,thiz:Object):Function {
			return function(...args2):* {
				return func.apply(thiz,args2);
			}
		}
		public static function formatStringArray(stringList:Array):String { //Changes an array of values into "1", "1 and 2" or "1, (x, )y, and z"
			switch (stringList.length) {
				case  0: return "";
				case  1: return stringList[0];
				case  2: return stringList[0] + ", and " + stringList[1]; //Now with 30% more Oxford
				default:
			}
			var concat:String = stringList[0];
			for (var x:int = 1; x < stringList.length - 1; x++) concat += ", " + stringList[x];
			return concat + " and " + stringList[stringList.length - 1];
		}
		public static function stringOr(input:*,def:String=""):String {
			return (input is String) ? input : def;
		}
		public static function intOr(input:*,def:int=0):int {
			return (input is int) ? input :
					(input is Number) ? input|0 : def;
		}
		public static function numberOr(input:*,def:Number=0):Number {
			return (input is Number) ? input : def;
		}
		public static function objectOr(input:*,def:Object=null):Object {
			return (input is Object && input !== null) ? input : def;
		}
		public static function boundInt(min:int, x:int, max:int):int {
			return x < min ? min : x > max ? max : x;
		}
		public static function boundFloat(min:Number, x:Number, max:Number):Number {
			if (!isFinite(x)) return min;
			return x < min ? min : x > max ? max : x;
		}
		public static function ipow(base:int,exponent:int):int {
			if (exponent<0) return 0;
			var x:int=1;
			while(exponent-->0) x*=base;
			return x;
		}
		/**
		 * Round (value) to (decimals) decimal digits
		 */
		public static function round(value:Number,decimals:int=0):Number {
			if (decimals<=0) return Math.round(value);
			var factor:Number = ipow(10,decimals);
			return Math.round(value*factor)/factor;
		}
		/**
		 * Round (value) up to (decimals) decimal digits
		 */
		public static function ceil(value:Number,decimals:int=0):Number {
			if (decimals<=0) return Math.ceil(value);
			var factor:Number = ipow(10,decimals);
			return Math.ceil(value*factor)/factor;
		}
		/**
		 * Round (value) down to (decimals) decimal digits
		 */
		public static function floor(value:Number,decimals:int=0):Number {
			if (decimals<=0) return Math.floor(value);
			var factor:Number = ipow(10,decimals);
			return Math.floor(value*factor)/factor;
		}
		/**
		 * Deleting obj[key] with default.
		 *
		 * If `key` in `obj`: return `obj[key]` and delete `obj[key]`
		 * Otherwise return `defaultValue`
		 */
		public static function moveValue(obj:Object,key:String,defaultValue:*):* {
			if (key in obj) {
				defaultValue = obj[key];
				delete obj[key];
			}
			return defaultValue;
		}
		/**
		 * Performs a shallow copy of properties from `src` to `dest`, then from `srcRest` to `dest`
		 * A `hasOwnProperties` check is performed.
		 */
		public static function extend(dest:Object, src:Object, ...srcRest:Array):Object {
			srcRest.unshift(src);
			for each(src in srcRest) {
				for (var k:String in src) {
					if (src.hasOwnProperty(k)) dest[k] = src[k];
				}
			}
			return dest;
		}
		/**
		 * Returns a shallow copy of `src` ownProperties
		 */
		public static function shallowCopy(src:Object):Object {
			return copyObject({},src);
		}
		/**
		 * Performs a shallow copy of properties from `src` to `dest`.
		 * If `properties` is supplied, only listed properties are copied.
		 * If not, all ownProperties of `src` are copied.
		 *
		 * @param properties array of property descriptors:
		 *

key:String
		 *     => dest[key] = src.key]

		 *
[dkey:String, skey:String]
		 *     => dest[dkey] = src[skey]
		 *
object with properties:
		 *

skey:String, dkey:String or key:String

		 *
(optional) 'default':*|Function to provide default value.
		 *         If function, called with no arguments

		 *

		 * @return dest
		 */
		public static function copyObject(dest:Object, src:Object,...properties:Array):Object {
			return copyObjectEx(dest, src, properties, true);
		}
		/**
		 * @see Utils.copyObject
		 * @param forward if true, use dest[dkey] and src[skey].
		 * if false, use dest[skey] and src[dkey].
		 * This option is useful when you have one set of descriptors to use it in both directions
		 * @param ignoreErrors If assignment throws an error, continue to next property.
		 * @return dest
		 */
		public static function copyObjectEx(dest:Object, src:Object, properties:Array, forward:Boolean = true, ignoreErrors:Boolean = false):Object {
			if (properties.length == 0) return extend(dest,src);
			for each (var pd:* in properties) {
				var skey:String,dkey:String,v:*;
				var def:*,hasDefault:Boolean=false;
				if (pd is String) {
					skey = pd;
					dkey = pd;
				} else if (pd is Array) {
					if (pd.length==2) {
						if (forward) {
							dkey = pd[0];
							skey = pd[1];
						}else {
							dkey = pd[1];
							skey = pd[0];
						}
					}
				} else if (pd is Object) {
					if ("key" in pd) {
						skey = dkey = pd.key;
					} else if ("skey" in pd && "dkey" in pd) {
						skey = pd.skey;
						dkey = pd.dkey;
					} else {
						LOGGER.warn("Missing 'key' or 'skey'+'dkey' in property descriptor {0}", pd);
						continue;
					}
					if (!forward) {
						// we can't do it in the assignment below because of the check
						var tmp:String = skey;
						skey = dkey;
						dkey = tmp;
					}
					if ("default" in pd) {
						def = pd["default"];
						hasDefault = true;
					}
				}
				if (skey in src) {
					v = src[skey];
				} else if (hasDefault) {
					if (def is Function) v = def();
					else v = def();
				} else continue;
				try {
					dest[dkey] = v;
				} catch (e:Error) {
					if (!ignoreErrors) throw e;
				}
			}
			return dest;
		}
		/**
		 * [ [key1,value1], [key2, value2], ... ] -> { key1: value1, key2: value2, ... }
		 */
		public static function createMapFromPairs(src:Array):Object {
			return multipleMapsFromPairs(src)[0];
		}
		/**
		 * [ [key1, value1_1, value1_2, ...],
		 *   [key2, value2_1, value2_2, ...], ... ]
		 *   ->
		 * [ { key1: value1_1,
		 *     key2: value2_1, ...
		 *   }, {
		 *     key1: value1_2,
		 *     key2: value2_2, ...
		 *   }, ... ]
		 */
		public static function multipleMapsFromPairs(src:Array):Array {
			var results:Array = [{}];
			for each(var tuple:Array in src) {
				while (results.length < tuple.length-1) results.push({});
				var key:* = tuple[0];
				for (var i:int = 1; i<tuple.length; i++) results[i-1][key] = tuple[i];
			}
			return results;
		}

		/**
		 * Convert a mixed array to an array of strings
		 *
		 * Some string lists (color lists for example) may contain strings and arrays containing 2+ strings.
		 * e. g.: ["blue", "green", ["black", "white", "gray"], ["red", "orange"], "blue"]
		 * With this method such an array would be converted to contain only string.
		 * So the above example would return:
		 * ["blue", "green", "black, white and gray", "red and orange", "blue"]
		 *
		 * @param   list  An array with mixed strings and arrays of strings
		 * @return  An array of strings
		 */
		public static function convertMixedToStringArray(list:Array):Array
		{
			var returnArray:Array = [];
			for (var i:String in list)
				returnArray.push((list[i] is Array) ? formatStringArray(list[i]) : list[i]);

			return returnArray;
		}

		public static function isObject(val:*):Boolean
		{
			return typeof val == "object" && val != null;
		}

		public static function num2Text(number:int):String {
			if (number >= 0 && number <= 10) return NUMBER_WORDS_NORMAL[number];
			return number.toString();
		}

		public static function num2Text2(number:int):String {
			if (number < 0) return number.toString(); //Can't really have the -10th of something
			if (number <= 10) return NUMBER_WORDS_POSITIONAL[number];

			return number.toString() + "th";
		}

		public static function Num2Text(number:int):String {
			if (number >= 0 && number <= 10) return NUMBER_WORDS_CAPITAL[number];
			return number.toString();
		}

		public static function addComma(num:int):String{
			var str:String = "";
			if (num <= 0) return "0";
			while (num>0){
				var tmp:uint = num % 1000;
				str = ( num > 999 ?"," + (tmp < 100 ? ( tmp < 10 ? "00": "0"): ""): "") + tmp + str;
				num = num / 1000;
			}
			return str;
		}

		public static function capitalizeFirstLetter(string:String):String {
			return (string.substr(0, 1).toUpperCase() + string.substr(1));
		}

		public static function lowercaseFirstLetter(string:String):String {
			return (string.substr(0, 1).toLowerCase() + string.substr(1));
		}

        /**
		 * If you don't understand this code just give up seriously smh tbh
         * @param flag - the number you want to check for bit count
         * @return the number of bits in that number that are set to 1
         */
		public static function countSetBits(flag:int):int{
            flag = flag - ((flag >> 1) & 0x55555555);
            flag = (flag & 0x33333333) + ((flag >> 2) & 0x33333333);
            return (((flag + (flag >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
		}

		/**
		 * Basically, you pass an arbitrary-length list of arguments, and it returns one of them at random. Accepts any type.
		 * Can also accept a *single* array of items, in which case it picks from the array instead.
		 * This lets you pre-construct the argument, to make things cleaner
		 *
		 * @param	...args arguments to pick from
		 * @return a randomly selected argument
		 */
		public static function randomChoice(...args):*
		{
			var tar:Array;

			if (args.length == 1 && args[0] is Array) tar = args[0];
			else if (args.length > 1) tar = args;
			else throw new Error("RandomInCollection could not determine usage pattern.");

			return tar[rand(tar.length)];
		}

		/**
		 * Utility function to search for a specific value within a target array or collection of values.
		 * Collection can be supplied either as an existing array or as varargs:
		 * ex: 	inCollection(myValue, myArray)
		 * 		inCollection(myValue, myPossibleValue1, myPossibleValue2, myPossibleValue3)
		 * @param	tar			Target value to search for
		 * @param	... args	Collection to look in
		 * @return				Boolean true/false if found/not found.
		 */
		public static function inCollection(tar:*, ... args):Boolean
		{
			if (args.length == 0) return false;

			var collection:*;

			for (var ii:int = 0; ii < args.length; ii++)
			{
				collection = args[ii];

				if (!(collection is Array))
				{
					if (tar == collection) return true;
				}
				else
				{
					for (var i:int = 0; i < collection.length; i++)
					{
						if (tar == collection[i]) return true;
					}
				}
			}

			return false;
		}

		/**
		 * Generate a random number from 0 to max - 1 inclusive.
		 * @param	max the upper limit for the generated number
		 * @return a number from 0 to max - 1 inclusive
		 */
		public static function rand(max:Number):int
		{
			return int(Math.random() * max);
		}
		public static function randBetween(min:Number, max:Number, inclusive:Boolean = true):int
		{
			if (inclusive) return int(Math.random() * (max - min + 1) + min);
			return int(Math.random() * (max - min - 1) + min + 1);
		}
		public static function trueOnceInN(n:Number):Boolean
		{
			return Math.random()*n < 1;
		}

		public static function validateNonNegativeNumberFields(o:Object, func:String, nnf:Array):String
		{
			var error:String = "";
			var propExists:Boolean;
			var fieldRef:*;
			for each (var field:String in nnf) {
				try {
					var value:* = Eval.eval(o, field);
					if (value === undefined || !(value is Number)) error += "Misspelling in "+func+".nnf: '"+field+"'. ";
					else if (value === null) error += "Null '"+field+"'. ";
					else if (value < 0) error += "Negative '"+field+"'. ";
				} catch (e:Error) {
					error += "Error calling eval on '"+func+"': "+e.message+". ";
				}
			}
			return error;
		}

		public static function validateNonEmptyStringFields(o:Object, func:String, nef:Array):String
		{
			var error:String = "";
			var propExists:Boolean;
			var fieldRef:*;
			for each (var field:String in nef) {
				try {
					var value:* = Eval.eval(o, field);
					if (value === undefined || !(value is String)) error += "Misspelling in " + func + ".nef: '" + field + "'. ";
					else if (value == null) error += "Null '" + field + "'. ";
					else if (value == "") error += "Empty '" + field + "'. ";
				} catch (e:Error) {
					error += "Error calling eval on '"+func+"': "+e.message+". ";
				}
			}
			return error;
		}
		/**
		 * numberOfThings(0,"brain") = "no brains"
		 * numberOfThings(1,"head") = "one head"
		 * numberOfThings(2,"tail") = "2 tails"
		 * numberOfThings(3,"hoof","hooves") = "3 hooves"
		 */
		public static function numberOfThings(n:int, name:String, pluralForm:String = null):String
		{
			pluralForm = pluralForm || (name + "s");
			if (n == 0) return "no " + pluralForm;
			if (n == 1) return "one " + name;
			return n + " " + pluralForm;
		}
		public static function pluralize(n:int, name:String, pluralForm:String = null):String {
			pluralForm = pluralForm || (name + "s");
			if (n == 1) return name;
			else return pluralForm;
		}

		public static function repeatString(s:String,n:int):String {
			var rslt:String = "";
			while (n-->0) rslt += s;
			return rslt;
		}
		public static function trimLeft(s:String):String {
			return s.replace(/^\s+/g,'');
		}
		public static function trimRight(s:String):String {
			return s.replace(/\s+$/g,'');
		}
		public static function trimSides(s:String):String {
			return trimLeft(trimRight(s));
		}

		public static function isEmptyObject(obj:Object):Boolean{
            var isEmpty:Boolean = true;
            for (var n:* in obj) { isEmpty = false; break; }
			return isEmpty;
		}

        public static function newSibling(sourceObj:Object):* {
            if(sourceObj) {

                var objSibling:*;
                try {
                    var classOfSourceObj:Class = getDefinitionByName(getQualifiedClassName(sourceObj)) as Class;
                    objSibling = new classOfSourceObj();
                }

                catch(e:Object) {}

                return objSibling;
            }
            return null;
        }

        public static function clone(source:Object):Object {

            var clone:Object;
            if(source) {
                clone = newSibling(source);

                if(clone) {
                    copyData(source, clone);
                }
            }

            return clone;
        }

        public static function copyData(source:Object, destination:Object):void {

            //copies data from commonly named properties and getter/setter pairs
            if((source) && (destination)) {

                try {
                    var sourceInfo:XML = describeType(source);
                    var prop:XML;

                    for each(prop in sourceInfo.variable) {

                        if(destination.hasOwnProperty(prop.@name)) {
                            destination[prop.@name] = source[prop.@name];
                        }

                    }

                    for each(prop in sourceInfo.accessor) {
                        if(prop.@access == "readwrite") {
                            if(destination.hasOwnProperty(prop.@name)) {
                                destination[prop.@name] = source[prop.@name];
                            }

                        }
                    }
                }
                catch (err:Object) {
                    ;
                }
            }
        }
	}
}


code:
package classes.internals
{
	/**
	 * Class for performing weighted random actions (function/method calls) derived from WeightedDrop by aimozg
	 * @since May 7, 2017
	 * @author Stadler76
	 */
	public class WeightedAction implements RandomAction
	{
		private var actions:Array = [];
		private var sum:Number = 0;

		public function WeightedAction(first:Function = null, firstWeight:Number = 0)
		{
			if (first != null) {
				actions.push([first,firstWeight]);
				sum += firstWeight;
			}
		}

		public function add(action:Function, weight:Number = 1):WeightedAction
		{
			actions.push([action, weight]);
			sum += weight;
			return this;
		}

		public function addMany(weight:Number, ..._actions):WeightedAction
		{
			for each (var action:Function in _actions) {
				actions.push([action, weight]);
				sum += weight;
			}
			return this;
		}

		public function exec():void
		{
			var random:Number = Math.random()*sum;
			var action:Function = null;
			var actions:Array = this.actions.slice();
			while (random > 0 && actions.length > 0) {
				var pair:Array = actions.shift();
				action = pair[0];
				random -= pair[1];
			}

			if (action != null)
				action();
		}

		public function clone():WeightedAction
		{
			var other:WeightedAction = new WeightedAction();
			other.actions = actions.slice();
			other.sum = sum;
			return other;
		}
	}
}


code:
package classes.internals
{
	/**
	 * Class for returning weighted random choices derived from WeightedDrop by aimozg
	 * @since March 7, 2018
	 * @author Stadler76
	 */
	public class WeightedChoice implements RandomChoice
	{
		private var choices:Array = [];
		private var sum:Number = 0;

		public function WeightedChoice(first:* = null, firstWeight:Number = 0)
		{
			if (first != null) {
				choices.push([first, firstWeight]);
				sum += firstWeight;
			}
		}

		public function add(choice:*, weight:Number = 1):WeightedChoice
		{
			choices.push([choice, weight]);
			sum += weight;
			return this;
		}

		public function addMany(weight:Number, ..._choices):WeightedChoice
		{
			for each (var choice:* in _choices){
				choices.push([choice, weight]);
				sum += weight;
			}
			return this;
		}

		public function choose():*
		{
			var random:Number = Math.random() * sum;
			var choice:* = null;
			var choices:Array = this.choices.slice();
			while (random > 0 && choices.length > 0) {
				var pair:Array = choices.shift();
				choice = pair[0];
				random -= pair[1];
			}
			return choice;
		}

		public function clone():WeightedChoice
		{
			var other:WeightedChoice = new WeightedChoice();
			other.choices = choices.slice();
			other.sum = sum;
			return other;
		}
	}
}


code:
/**
 * Created by aimozg on 11.01.14.
 */
package classes.internals
{
	public class WeightedDrop implements RandomDrop
	{
		private var items:Array = [];
		private var sum:Number = 0;
		public function WeightedDrop(first:*=null,firstWeight:Number=0)
		{
			if (first != null){
				items.push([first,firstWeight]);
				sum += firstWeight;
			}
		}
		public function add(item:*,weight:Number=1):WeightedDrop
		{
			items.push([item,weight]);
			sum += weight;
			return this;
		}
		public function addMany(weight:Number,..._items):WeightedDrop
		{
			for each (var item:* in _items){
				items.push([item,weight]);
				sum += weight;
			}
			return this;
		}
		// you can pass your own random value from 0 to 1 (so you can use your own RNG)
		public function roll():*
		{
			var random:Number = Math.random()*sum;
			var item:* = null;
			var items:Array = this.items.slice();
			while (random > 0 && items.length > 0) {
				var pair:Array = items.shift();
				item = pair[0];
				random -= pair[1];
			}
			return item;
		}

		public function clone():WeightedDrop
		{
			var other:WeightedDrop = new WeightedDrop();
			other.items = items.slice();
			other.sum = sum;
			return other;
		}
	}
}


code:
/**
 * Created by aimozg on 13.05.2017.
 */
package classes.internals.profiling {
import classes.internals.Profiling;

public function Begin(classname:String, methodName:String, ...rest:Array):void {
	Profiling.Begin.apply(null,[classname,methodName].concat(rest));
}
}


code:
/**
 * Created by aimozg on 13.05.2017.
 */
package classes.internals.profiling {
import classes.internals.Profiling;

public function End(classname:String, methodName:String):void {
	Profiling.End(classname,methodName);
}
}


code:
package classes.lists
{
	/**
	 * Container class for the gender constants
	 * @since November 08, 2017
	 * @author Stadler76
	 */
	public class Age
	{
		public static const AGE_ADULT:int                                                   =    0;
		public static const AGE_CHILD:int                                                   =    1;
		public static const AGE_TEEN:int                                                    =    2;
		public static const AGE_ELDER:int                                                   =    3;

		public function Age() {}
	}
}


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

	/**
	 * Class for BodyPart lists
	 * @since August 08, 2017
	 * @author Stadler76
	 */
	public class BodyPartLists
	{
		/**
		 * Echidna 1 ft long (i'd consider it barely qualifying), demonic 2 ft long, draconic 4 ft long
		 */
		public static const LONG_TONGUES:Array = [
			Tongue.DEMONIC,
			Tongue.DRACONIC,
			Tongue.ECHIDNA,
		];

		public static const CAN_FLY_WINGS:Array = [
			Wings.BEE_LIKE_LARGE,
			Wings.BAT_LIKE_LARGE,
			Wings.FEATHERED_LARGE,
			Wings.DRACONIC_LARGE,
			Wings.GIANT_DRAGONFLY,
			Wings.IMP_LARGE,
			Wings.HARPY,
		];

		public static const MUZZLES:Array = [
			Face.HORSE,
			Face.DOG,
			Face.CAT,
			Face.LIZARD,
			Face.KANGAROO,
			Face.FOX,
			Face.DRAGON,
			Face.RHINO,
			Face.ECHIDNA,
			Face.DEER,
			Face.WOLF,
			Face.RED_PANDA,
		];

		public static const HUMANISH_FACES:Array = [
			Face.HUMAN,
			Face.SHARK_TEETH,
			Face.SNAKE_FANGS,
			Face.SPIDER_FANGS,
		];

		public static const LONG_TAILS:Array = [
			Tail.DOG,
			Tail.DEMONIC,
			Tail.COW,
			Tail.SHARK,
			Tail.CAT,
			Tail.LIZARD,
			Tail.KANGAROO,
			Tail.FOX,
			Tail.DRACONIC,
			Tail.RACCOON,
			Tail.MOUSE,
			Tail.FERRET,
			Tail.BEHEMOTH,
			Tail.SCORPION,
			Tail.SALAMANDER,
			Tail.WOLF,
			Tail.IMP,
			Tail.COCKATRICE,
			Tail.RED_PANDA,
		];
	}
}


code:
package classes.lists
{
	/**
	 * Container class for the breastcup constants
	 * @since November 09, 2017
	 * @author Stadler76
	 */
	public class BreastCup
	{
		public static const FLAT:int            =   0;
		public static const A:int               =   1;
		public static const B:int               =   2;
		public static const C:int               =   3;
		public static const D:int               =   4;
		public static const DD:int              =   5;
		public static const DD_BIG:int          =   6;
		public static const E:int               =   7;
		public static const E_BIG:int           =   8;
		public static const EE:int              =   9;
		public static const EE_BIG:int          =  10;
		public static const F:int               =  11;
		public static const F_BIG:int           =  12;
		public static const FF:int              =  13;
		public static const FF_BIG:int          =  14;
		public static const G:int               =  15;
		public static const G_BIG:int           =  16;
		public static const GG:int              =  17;
		public static const GG_BIG:int          =  18;
		public static const H:int               =  19;
		public static const H_BIG:int           =  20;
		public static const HH:int              =  21;
		public static const HH_BIG:int          =  22;
		public static const HHH:int             =  23;
		public static const I:int               =  24;
		public static const I_BIG:int           =  25;
		public static const II:int              =  26;
		public static const II_BIG:int          =  27;
		public static const J:int               =  28;
		public static const J_BIG:int           =  29;
		public static const JJ:int              =  30;
		public static const JJ_BIG:int          =  31;
		public static const K:int               =  32;
		public static const K_BIG:int           =  33;
		public static const KK:int              =  34;
		public static const KK_BIG:int          =  35;
		public static const L:int               =  36;
		public static const L_BIG:int           =  37;
		public static const LL:int              =  38;
		public static const LL_BIG:int          =  39;
		public static const M:int               =  40;
		public static const M_BIG:int           =  41;
		public static const MM:int              =  42;
		public static const MM_BIG:int          =  43;
		public static const MMM:int             =  44;
		public static const MMM_LARGE:int       =  45;
		public static const N:int               =  46;
		public static const N_LARGE:int         =  47;
		public static const NN:int              =  48;
		public static const NN_LARGE:int        =  49;
		public static const O:int               =  50;
		public static const O_LARGE:int         =  51;
		public static const OO:int              =  52;
		public static const OO_LARGE:int        =  53;
		public static const P:int               =  54;
		public static const P_LARGE:int         =  55;
		public static const PP:int              =  56;
		public static const PP_LARGE:int        =  57;
		public static const Q:int               =  58;
		public static const Q_LARGE:int         =  59;
		public static const QQ:int              =  60;
		public static const QQ_LARGE:int        =  61;
		public static const R:int               =  62;
		public static const R_LARGE:int         =  63;
		public static const RR:int              =  64;
		public static const RR_LARGE:int        =  65;
		public static const S:int               =  66;
		public static const S_LARGE:int         =  67;
		public static const SS:int              =  68;
		public static const SS_LARGE:int        =  69;
		public static const T:int               =  70;
		public static const T_LARGE:int         =  71;
		public static const TT:int              =  72;
		public static const TT_LARGE:int        =  73;
		public static const U:int               =  74;
		public static const U_LARGE:int         =  75;
		public static const UU:int              =  76;
		public static const UU_LARGE:int        =  77;
		public static const V:int               =  78;
		public static const V_LARGE:int         =  79;
		public static const VV:int              =  80;
		public static const VV_LARGE:int        =  81;
		public static const W:int               =  82;
		public static const W_LARGE:int         =  83;
		public static const WW:int              =  84;
		public static const WW_LARGE:int        =  85;
		public static const X:int               =  86;
		public static const X_LARGE:int         =  87;
		public static const XX:int              =  88;
		public static const XX_LARGE:int        =  89;
		public static const Y:int               =  90;
		public static const Y_LARGE:int         =  91;
		public static const YY:int              =  92;
		public static const YY_LARGE:int        =  93;
		public static const Z:int               =  94;
		public static const Z_LARGE:int         =  95;
		public static const ZZ:int              =  96;
		public static const ZZ_LARGE:int        =  97;
		public static const ZZZ:int             =  98;
		public static const ZZZ_LARGE:int       =  99;
		public static const HYPER_A:int         = 100;
		public static const HYPER_B:int         = 101;
		public static const HYPER_C:int         = 102;
		public static const HYPER_D:int         = 103;
		public static const HYPER_DD:int        = 104;
		public static const HYPER_DD_BIG:int    = 105;
		public static const HYPER_E:int         = 106;
		public static const HYPER_E_BIG:int     = 107;
		public static const HYPER_EE:int        = 108;
		public static const HYPER_EE_BIG:int    = 109;
		public static const HYPER_F:int         = 110;
		public static const HYPER_F_BIG:int     = 111;
		public static const HYPER_FF:int        = 112;
		public static const HYPER_FF_BIG:int    = 113;
		public static const HYPER_G:int         = 114;
		public static const HYPER_G_BIG:int     = 115;
		public static const HYPER_GG:int        = 116;
		public static const HYPER_GG_BIG:int    = 117;
		public static const HYPER_H:int         = 118;
		public static const HYPER_H_BIG:int     = 119;
		public static const HYPER_HH:int        = 120;
		public static const HYPER_HH_BIG:int    = 121;
		public static const HYPER_HHH:int       = 122;
		public static const HYPER_I:int         = 123;
		public static const HYPER_I_BIG:int     = 124;
		public static const HYPER_II:int        = 125;
		public static const HYPER_II_BIG:int    = 126;
		public static const HYPER_J:int         = 127;
		public static const HYPER_J_BIG:int     = 128;
		public static const HYPER_JJ:int        = 129;
		public static const HYPER_JJ_BIG:int    = 130;
		public static const HYPER_K:int         = 131;
		public static const HYPER_K_BIG:int     = 132;
		public static const HYPER_KK:int        = 133;
		public static const HYPER_KK_BIG:int    = 134;
		public static const HYPER_L:int         = 135;
		public static const HYPER_L_BIG:int     = 136;
		public static const HYPER_LL:int        = 137;
		public static const HYPER_LL_BIG:int    = 138;
		public static const HYPER_M:int         = 139;
		public static const HYPER_M_BIG:int     = 140;
		public static const HYPER_MM:int        = 141;
		public static const HYPER_MM_BIG:int    = 142;
		public static const HYPER_MMM:int       = 143;
		public static const HYPER_MMM_LARGE:int = 144;
		public static const HYPER_N:int         = 145;
		public static const HYPER_N_LARGE:int   = 146;
		public static const HYPER_NN:int        = 147;
		public static const HYPER_NN_LARGE:int  = 148;
		public static const HYPER_O:int         = 149;
		public static const HYPER_O_LARGE:int   = 150;
		public static const HYPER_OO:int        = 151;
		public static const HYPER_OO_LARGE:int  = 152;
		public static const HYPER_P:int         = 153;
		public static const HYPER_P_LARGE:int   = 154;
		public static const HYPER_PP:int        = 155;
		public static const HYPER_PP_LARGE:int  = 156;
		public static const HYPER_Q:int         = 157;
		public static const HYPER_Q_LARGE:int   = 158;
		public static const HYPER_QQ:int        = 159;
		public static const HYPER_QQ_LARGE:int  = 160;
		public static const HYPER_R:int         = 161;
		public static const HYPER_R_LARGE:int   = 162;
		public static const HYPER_RR:int        = 163;
		public static const HYPER_RR_LARGE:int  = 164;
		public static const HYPER_S:int         = 165;
		public static const HYPER_S_LARGE:int   = 166;
		public static const HYPER_SS:int        = 167;
		public static const HYPER_SS_LARGE:int  = 168;
		public static const HYPER_T:int         = 169;
		public static const HYPER_T_LARGE:int   = 170;
		public static const HYPER_TT:int        = 171;
		public static const HYPER_TT_LARGE:int  = 172;
		public static const HYPER_U:int         = 173;
		public static const HYPER_U_LARGE:int   = 174;
		public static const HYPER_UU:int        = 175;
		public static const HYPER_UU_LARGE:int  = 176;
		public static const HYPER_V:int         = 177;
		public static const HYPER_V_LARGE:int   = 178;
		public static const HYPER_VV:int        = 179;
		public static const HYPER_VV_LARGE:int  = 180;
		public static const HYPER_W:int         = 181;
		public static const HYPER_W_LARGE:int   = 182;
		public static const HYPER_WW:int        = 183;
		public static const HYPER_WW_LARGE:int  = 184;
		public static const HYPER_X:int         = 185;
		public static const HYPER_X_LARGE:int   = 186;
		public static const HYPER_XX:int        = 187;
		public static const HYPER_XX_LARGE:int  = 188;
		public static const HYPER_Y:int         = 189;
		public static const HYPER_Y_LARGE:int   = 190;
		public static const HYPER_YY:int        = 191;
		public static const HYPER_YY_LARGE:int  = 192;
		public static const HYPER_Z:int         = 193;
		public static const HYPER_Z_LARGE:int   = 194;
		public static const HYPER_ZZ:int        = 195;
		public static const HYPER_ZZ_LARGE:int  = 196;
		public static const HYPER_ZZZ:int       = 197;
		public static const HYPER_ZZZ_LARGE:int = 198;
		public static const JACQUES00:int       = 199;
	}
}


code:
package classes.lists {
	public class BtnCol {
		public function BtnCol() {}

		public static const DEFAULT:Array		= [1, 1, 1];
		public static const MAGIC_WHITE:Array	= [1, 1, 1];//[1.6, 1.8, 2.2];
		public static const MAGIC_BLACK:Array	= [1, 1, 1];//[0.5, 0.5, 0.7];
		public static const MAGIC_GRAY:Array	= [1, 1, 1];//[1.1, 1.2, 1.4];
		public static const TF_FIRE:Array		= [1, 1, 1];//[0.7, 1.1, 0.3];
		public static const TF_EARTH:Array		= [1, 1, 1];//[0.8, 0.6, 0.4];
		public static const TF_FUSION:Array		= [1, 1, 1];//[1.3, 1.3, 0.4];

	}
}


code:
package classes.lists
{
	/**
	 * Container class for color lists
	 * @since December 02, 2017
	 * @author Stadler76
	 */
	public class ColorLists
	{
		public static const HUMAN_SKIN:Array = [
			"light",
			"fair",
			"olive",
			"dark",
			"ebony",
			"mahogany",
			"russet",
		];

		public static const GOBLIN_SKIN:Array = [
			"pale yellow",
			"grayish-blue",
			"green",
			"dark green",
		];

		public static const GOO_MORPH:Array = [
			"green",
			"purple",
			"blue",
			"cerulean",
			"emerald",
		];

		public static const IMP_SKIN:Array = [
			"red",
			"orange",
		];

		public static const SALAMANDER_SKIN:Array = [
			"light",
			"fair",
			"tan",
			"dark",
		];

		public static const RED_PANDA_HAIR:Array = [
			"white",
			"auburn",
			"red",
			"russet",
		];

		public static const RED_PANDA_TAIL:Array = [
			["auburn",  "russet"],
			["black",   "gray"],
			["blond",   "sandy-blonde"],
			["brown",   "auburn"],
			["red",     "orange"],
			["white",   "gray"],
			["gray",    "white"],
			["blue",    "light-blue"],
			["green",   "chartreuse"],
			["orange",  "yellow"],
			["yellow",  "sandy-blonde"],
			["purple",  "pink"],
			["pink",    "purple"],
			["rainbow", "white"],
			["russet",  "orange"],
		];

		public static const HORSE_FUR:Array = [
			"brown",
			"chocolate",
			"auburn",
			"sandy brown",
			"caramel",
			"peach",
			"black",
			"midnight black",
			"dark gray",
			"gray",
			"light gray",
			"silver",
			"white",
			"brown and white",
			"black and white",
		];

		public static const CAT_FUR:Array = [
			"brown",
			"chocolate",
			"auburn",
			"caramel",
			"orange",
			"sandy brown",
			"golden",
			"black",
			"midnight black",
			"dark gray",
			"gray",
			"light gray",
			"silver",
			"white",
			["orange", "white"],
			["brown", "white"],
			["black", "white"],
			["gray", "white"],
		];

		public static const DOG_FUR:Array = [
			"brown",
			"chocolate",
			"auburn",
			"caramel",
			"orange",
			"black",
			"dark gray",
			"gray",
			"light gray",
			"silver",
			"white",
			"orange and white",
			"brown and white",
			"black and white",
		];

		public static const FOX_FUR:Array = [
			["orange", "white"],
			["orange", "white"],
			["orange", "white"],
			["red", "white"],
			["black", "white"],
			"white",
			"tan",
			"brown",
		];

		public static const FERRET_HAIR:Array = [
			"white",
			"brown",
			"caramel",
		];

		public static const FERRET_FUR:Array = [
			["brown",         "brown"],
			["brown",         "black"],
			["light brown",   "caramel"],
			["caramel",       "caramel"],
			["caramel",       "cream"],
			["silver",        "silver"],
			["white",         "white"],
			["sandy brown",   "brown"],
			["sapphire blue", "electric blue"],
		];

		public static const BASIC_KITSUNE_HAIR:Array = [
			"white",
			"black",
			"black",
			"black",
			"red",
			"red",
			"red",
		];

		public static const BASIC_KITSUNE_FUR:Array = [
			["orange", "white"],
			"black",
			["black", "white"],
			"red",
			["red", "white"],
			"white",
		];

		public static const ELDER_KITSUNE:Array = [
			"metallic golden",
			"golden blonde",
			"metallic silver",
			"silver blonde",
			"snow white",
			"iridescent gray",
		];

		public static const KITSUNE_SKIN:Array = [
			"tan",
			"olive",
			"light",
		];

		public static const KITSUNE_SKIN_MYSTIC:Array = [
			"dark",
			"ebony",
			"ashen",
			"sable",
			"milky white",
		];

		public static const COCKATRICE:Array = [
			["blue",   "turquoise", "blue"],
			["orange", "red",       "orange"],
			["green",  "yellow",    "green"],
			["purple", "pink",      "purple"],
			["black",  "white",     "black"],
			["blonde", "brown",     "blonde"],
			["white",  "gray",      "white"],
		];

		public static const NAGA_LOWERBODY:Array = [
			["red",          "orange"],
			["orange",       "yellow"],
			["yellow",       "yellowgreen"],
			["yellowgreen",  "yellow"],
			["green",        "light green"],
			["spring green", "cyan"],
			["cyan",         "ocean blue"],
			["ocean blue",   "light blue"],
			["blue",         "light blue"],
			["purple",       "light purple"],
			["magenta",      "blue"],
			["deep pink",    "pink"],
			["black",        "dark gray"],
			["white",        "light gray"],
			["gray",         "light gray"],
			["light gray",   "white"],
			["dark gray",    "gray"],
			["pink",         "pale pink"],
		];
	}
}


code:
package classes.lists
{
	import classes.GlobalFlags.kFLAGS;
	/**
	 * Class for flag lists
	 * @since August 01, 2018
	 * @author Stadler76
	 */
	public class FlagLists
	{
		public static const KEEP_ON_ASCENSION:Array = [
			kFLAGS.NEW_GAME_PLUS_LEVEL,
			kFLAGS.GAME_DIFFICULTY,
			kFLAGS.HUNGER_ENABLED,
			kFLAGS.HARDCORE_MODE,
			kFLAGS.HARDCORE_SLOT,
			kFLAGS.ASCENSIONING,
			kFLAGS.UNLOCKED_ASCENSION_AGE,
		];
	}
}


code:
package classes.lists
{
	/**
	 * Container class for the gender constants
	 * @since November 08, 2017
	 * @author Stadler76
	 */
	public class Gender
	{
		public static const ANY:int    = -1;
		public static const NONE:int   = 0;
		public static const MALE:int   = 1;
		public static const FEMALE:int = 2;
		public static const HERM:int   = 3;
	}
}


code:
package classes.lists
{
	import classes.CockTypesEnum;
	/**
	 * Class for Genital lists
	 * @since September 29, 2018
	 * @author Stadler76
	 */
	public class GenitalLists
	{
		/**
		 * Contains cock types that support knots.
		 * This is used for the supportsKnot method and with that to decide if a knot is reset when the cock type changes
		 * e.g. player.cocks[0].cockType = CockTypesEnum.HORSE
		 */
		public static const KNOTTED_COCKS:Vector.<CockTypesEnum> = new <CockTypesEnum>[
			CockTypesEnum.DOG,
			CockTypesEnum.FOX,
			CockTypesEnum.WOLF,
			CockTypesEnum.DRAGON,
			CockTypesEnum.DISPLACER
		];
	}
}


code:
package classes.lists
{
	import classes.PerkLib;

	/**
	 * Class for Perk lists
	 * @since November 28, 2017
	 * @author Stadler76
	 */
	public class PerkLists
	{
		public static const PERMEABLE:Array = [
			//Transformation Perks
			PerkLib.Flexibility,
			PerkLib.Incorporeality,
			PerkLib.SatyrSexuality,
			PerkLib.Lustzerker,
			PerkLib.CorruptedNinetails,
			PerkLib.EnlightenedNinetails,
			//Marae's Perks
			PerkLib.MaraesGiftButtslut,
			PerkLib.MaraesGiftFertility,
			PerkLib.MaraesGiftProfractory,
			PerkLib.MaraesGiftStud,
			PerkLib.PurityBlessing,
			//Fire Breath Perks
			PerkLib.Hellfire,
			PerkLib.FireLord,
			PerkLib.Dragonfire,
			//Other Perks
			PerkLib.Androgyny,
			PerkLib.MagicalFertility,
			PerkLib.MagicalVirility,
			PerkLib.MilkMaid,
			PerkLib.Misdirection,
			PerkLib.MysticLearnings,
			PerkLib.RapierTraining,
			PerkLib.PotentPregnancy,
			PerkLib.PotentProstate,
			PerkLib.ParasiteQueen,
			PerkLib.ThickSkin,
			PerkLib.TerrestrialFire
		];

		public static const BIMBO:Array = [
			PerkLib.BimboBody,
			PerkLib.BimboBrains,
			PerkLib.FutaForm,
			PerkLib.FutaFaculties,
		];

		public static const HISTORY:Array = [
			{ text: "Alchemy",		perk: PerkLib.HistoryAlchemist },
			{ text: "Fighting",		perk: PerkLib.HistoryFighter },
			{ text: "Fortune",		perk: PerkLib.HistoryFortune },
			{ text: "Healing",		perk: PerkLib.HistoryHealer },
			{ text: "Religion",		perk: PerkLib.HistoryReligious },
			{ text: "Schooling",	perk: PerkLib.HistoryScholar },
			{ text: "Slacking",		perk: PerkLib.HistorySlacker },
			{ text: "Slutting",		perk: PerkLib.HistorySlut },
			{ text: "Smithing",		perk: PerkLib.HistorySmith },
			{ text: "Whoring",		perk: PerkLib.HistoryWhore },
			{ text: "Alchemist",	perk: PerkLib.HistoryAlchemist2 },
			{ text: "Guard",		perk: PerkLib.HistoryFighter2 },
			{ text: "Gambler",		perk: PerkLib.HistoryFortune2 },
			{ text: "Healer",		perk: PerkLib.HistoryHealer2 },
			{ text: "Monk",			perk: PerkLib.HistoryReligious2 },
			{ text: "Teacher",		perk: PerkLib.HistoryScholar2 },
			{ text: "Thief",		perk: PerkLib.HistoryThief2 },
			{ text: "Libertine",	perk: PerkLib.HistorySlut2 },
			{ text: "Smith",		perk: PerkLib.HistorySmith2 },
			{ text: "Brothel Owner",perk: PerkLib.HistoryWhore2 },
			{ text: "Paladin",		perk: PerkLib.HistoryDEUSVULT },
		];

		public static const ENDOWMENT_ATTRIBUTE:Array = [
			{ text: "Strong",     perk: PerkLib.Strong },
			{ text: "Tough",      perk: PerkLib.Tough },
			{ text: "Fast",       perk: PerkLib.Fast },
			{ text: "Smarts",     perk: PerkLib.Smart },
			{ text: "Libido",     perk: PerkLib.Lusty },
			{ text: "Touch",      perk: PerkLib.Sensitive },
			{ text: "Perversion", perk: PerkLib.Pervert },
		];

		public static const ENDOWMENT_COCK:Array = [
			{ text: "Big Cock",     perk: PerkLib.BigCock },
			{ text: "Lots of Jizz", perk: PerkLib.MessyOrgasms },
		];

		public static const ENDOWMENT_VAGINA:Array = [
			{ text: "Big Breasts", perk: PerkLib.BigTits },
			{ text: "Big Clit",    perk: PerkLib.BigClit },
			{ text: "Fertile",     perk: PerkLib.Fertile },
			{ text: "Wet Vagina",  perk: PerkLib.WetPussy },
		];
	}
}


code:
package classes.menus
{
	import classes.Player;
	import classes.internals.GuiOutput;
	import classes.internals.GuiInput;
	import classes.lists.BreastCup;
	import mx.utils.StringUtil;

	/**
	 * Debug menu to add / remove gender related parts.
	 */
	public class GenderDebug implements Menu
	{
		public static const BUTTON_NAME:String = "Gender";
		public static const BUTTON_HINT:String = "Add and remove parts related to gender";

		private var player:Player;
		private var gui:GuiInput;
		private var output:GuiOutput;
		private var onMenuExit:Function;

		public function GenderDebug(gui:GuiInput, output:GuiOutput, player:Player, onMenuExit:Function)
		{
			this.player = player;
			this.gui = gui;
			this.output = output;
			this.onMenuExit = onMenuExit;
		}

		private function printMenuHeader():void {
			output.clear();

			output.header("Gender debug menu");
			output.text("<b>Use at your own risk!</b>\n");
			output.text("This menu allows you to create game states that are not possible during normal gameplay, you might want to create a backup save just to be sure.\n\n");
		}

		private function printGenderStats():void {
			output.text("Current body state:\n\n");

			output.text(StringUtil.substitute("You have {0} vagina(s)\n", player.vaginas.length));
			output.text(StringUtil.substitute("You have {0} cock(s)\n", player.cocks.length));
			output.text(StringUtil.substitute("You have {0} ball(s)\n", player.balls));
			output.text(StringUtil.substitute("You have {0} breast row(s)\n", player.breastRows.length));
		}

		private function refreshMenuText():void {
			printMenuHeader();
			printGenderStats();
			output.flush();
		}

		public function enter():void
		{
			refreshMenuText();
			gui.menu();

			gui.addButton(0, "Remove Vaginas", removeVaginas).hint("Removes ALL vaginas");
			gui.addButton(1, "Remove Cocks", removeCocks).hint("Removes ALL cocks");
			gui.addButton(2, "Remove Balls", removeBalls).hint("Removes 2 balls");
			gui.addButton(3, "Remove Breasts", removeBreasts).hint("Removes ALL breasts");

			gui.addButton(5, "Add Vagina", addVagina);
			gui.addButton(6, "Add Cock", addCock);
			gui.addButton(7, "Add Balls", addBalls).hint("Adds 2 balls");
			gui.addButton(8, "Add Breasts", addBreasts).hint("Adds a row of breasts");

			gui.addButton(9, "Back", onMenuExit);
		}

		public function getButtonText():String
		{
			return BUTTON_NAME;
		}

		public function getButtonHint():String
		{
			return BUTTON_HINT;
		}

		public function removeVaginas(): void {
			while (player.hasVagina()) {
				player.removeVagina();
			}

			refreshMenuText();
		}

		public function removeCocks(): void {
			while (player.hasCock()) {
				player.removeCock(0, 1);
			}

			refreshMenuText();
		}

		public function addCock(): void {
			player.createCock();
			refreshMenuText();
		}

		public function addVagina(): void {
			player.createVagina();
			refreshMenuText();
		}

		public function removeBalls(): void {
			player.balls -= 2;

			if (player.balls < 0) {
				player.balls = 0;
			}

			refreshMenuText();
		}

		public function addBalls(): void {
			player.balls += 2;
			refreshMenuText();
		}

		public function removeBreasts():void {
			while (player.breastRows.length > 1) {
				player.removeBreastRow(0, 1);
			}

			// make sure the last pair of breasts are flat
			if (player.hasBreasts()) {
				player.breastRows[0].breastRating = 0;
			}

			refreshMenuText();
		}

		public function addBreasts(): void {
			player.createBreastRow(BreastCup.A);
			refreshMenuText();
		}
	}
}


code:
package classes.menus
{
	/**
	 * Interface for GUI menus, which are a collection of buttons
	 */
	public interface Menu {
		/**
		 * This function is used as the entry point into the menu.
		 * It is usually responsible for drawing the menu.
		 */
		function enter(): void;

		/**
		 * Returns the text that should be displayed in a button that will
		 * call this menu.
		 *
		 * @return the button text for this menu
		 */
		function getButtonText(): String;

		/**
		 * Returns the hint text for the Button that calls this menu.
		 *
		 * @return the button hint for this menu.
		 */
		function getButtonHint(): String;
	}
}


code:
package classes
{
	/**
	 * ...
	 * @author Gedan
	 */
	public class room
	{
		public function room()
		{

		}

		public var RoomName:String; // Index name
		public var RoomDisplayName:String; // Header text

		public var NorthExit:String;
		public var NorthExitCondition:Function;
		public var NorthExitTime:int = 0;

		public var EastExit:String;
		public var EastExitCondition:Function;
		public var EastExitTime:int = 0;

		public var SouthExit:String;
		public var SouthExitCondition:Function;
		public var SouthExitTime:int = 0;

		public var WestExit:String;
		public var WestExitCondition:Function;
		public var WestExitTime:int = 0;

		public var RoomFunction:Function;
	}
}


code:
package classes.saves {

public final class SelfSaver {
	private static var saveList:Vector.<SelfSaving> = new Vector.<SelfSaving>();
	private static var filter:Function = function (item:SelfSaving, index:int, vector:Vector.<SelfSaving>):Boolean {
		return item.saveName == this;
	};

	public static function register(saver:SelfSaving):void {
		var filtered:Vector.<SelfSaving> = saveList.filter(filter, saver.saveName);
		if (filtered.length != 0) {
			throw "Self Saving Class already registered"
		} else {
			saveList.push(saver);
		}
	}

	public static function load(saveObj:Object):void {
		for each (var saver:SelfSaving in saveList) {
			saver.reset();
		}
		for (var save:String in saveObj) {
			var filtered:Vector.<SelfSaving> = saveList.filter(filter, save);
			if (filtered.length == 1) {
				filtered[0].load(saveObj[save].version, saveObj[save].data);
			} else {
				trace("Unknown self save object: " + save);
			}
		}
	}

	public static function save():Object {
		var toReturn:Object = {};
		for each (var saver:SelfSaving in saveList) {
			toReturn[saver.saveName] = {
				version: saver.saveVersion,
				data: saver.saveToObject()
			};
		}
		return toReturn;
	}

	public static function ascend(reset:Boolean):void {
		for each (var saver:SelfSaving in saveList) {
			saver.onAscend(reset);
		}
	}

	public function SelfSaver() {
		throw "Static Class"
	}
}
}


code:
package classes.saves {

import internals.Jsonable;

public interface SelfSaving extends Jsonable{
	function get saveName():String
	function get saveVersion():int
	function load(version:int, saveObject:Object):void
	function reset():void
	function onAscend(reset:Boolean):void
}
}


code:
package classes.saves {

public class SelfSavingFunctionWrapper implements SelfSaving {
	public function SelfSavingFunctionWrapper(fun:Function) {
		if (fun() is SelfSaving) {
			objectFun = fun;
		} else {
			throw "Function does not return a SelfSaving object.";
		}
	}
	private var objectFun:Function;

	public function get saveName():String {
		return objectFun().saveName;
	}

	public function get saveVersion():int {
		return objectFun().saveVersion;
	}

	public function load(version:int, saveObject:Object):void {
		objectFun().load(version, saveObject);
	}

	public function saveToObject():Object {
		return objectFun().saveToObject();
	}

	public function loadFromObject(o:Object, ignoreErrors:Boolean):void {
		objectFun().loadFromObject(o, ignoreErrors);
	}

	public function reset():void {
		objectFun().reset();
	}
}
}


code:
/**
 * Coded by aimozg on 12.07.2017.
 */
package coc.script {
import classes.internals.Utils;

public class Eval {
	// (condition,then,elze) => ()=>(condition()?then():elze())
	public static function functionIf(condition:Function,then:Function,elze:Function):Function {
		return function ():* {
			return condition() ? then() : elze();
		};
	}

	private var scopes:/*Object*/Array;
	private var expr:String;
	private var _src:String;
	private var _call:Function;
	public function call(...scopes:/*Object*/Array):* {
		return vcall(scopes);
	}
	public function get src():String {
		return _src;
	}
	public function vcall(scopes:/*Object*/Array):* {
		this.scopes = scopes;
		try {
			return _call();
		} catch (e:Error){
			throw error(_src,"",e.message,false);
		}
	}

	public function Eval(thiz:*, expr:String) {
		this.scopes = [thiz];
		this._src   = expr;
		this.expr   = expr;
	}

	private static const RX_FLOAT:RegExp = /^[+\-]?(\d+(\.\d+)?|\.\d+)(e[+\-]?\d+)?$/;
	private static const RX_INT:RegExp = /^[+\-]?(0x)?\d+$/;

	private static const LA_BLOCK_COMMENT:RegExp = /^\/\*([^*\/]|\*[^\/]|[^\*]\/)*\*+\//;
	private static const LA_FLOAT:RegExp = /^[+\-]?(\d+(\.\d+)?|\.\d+)(e[+\-]?\d+)?/;
	private static const LA_INT:RegExp = /^[+\-]?(0x)?\d+/;
	private static const LA_ID:RegExp = /^[a-zA-Z_$][a-zA-Z_$0-9]*/;
	private static const LA_OPERATOR:RegExp = /^(>=?|<=?|!==?|={1,3}|\|\||&&|or|and|eq|neq?|[lg](te|t|e)|[-+*\/%])/;
	private static const OP_PRIORITIES:* = {
		'||' : 10,
		'or' : 10,
		'&&' : 20,
		'and': 20,
		'>=' : 30,
		'>'  : 30,
		'<=' : 30,
		'<'  : 30,
		'!==': 30,
		'!=' : 30,
		'===': 30,
		'==' : 30,
		'='  : 30,
		'lt' : 30,
		'le' : 30,
		'lte': 30,
		'gt' : 30,
		'ge' : 30,
		'gte': 30,
		'neq': 30,
		'ne' : 30,
		'eq' : 30,
		'+'  : 40,
		'-'  : 40,
		'*'  : 50,
		'/'  : 50,
		'%'  : 50
	};
	public static function eval(thiz:*, expr:String):* {
		if (expr.match(RX_INT)) return int(expr);
		return new Eval(thiz, expr).evalUntil("")();
	}
	public static function evalScoped(expr:String,...scopes:/*Object*/Array):* {
		return evalVScoped(expr,scopes);
	}
	public static function evalVScoped(expr:String,scopes:/*Object*/Array):* {
		if (expr.match(RX_INT)) return int(expr);
		return compile(expr).vcall(scopes);
	}
	public static function compile(expr:String):Eval {
		var e:Eval = new Eval({}, expr);
		if (expr.match(RX_INT)) {
			const i:int = parseInt(expr);
			e._call     = function ():int {return i;};
		} else if (expr.match(RX_FLOAT)) {
			const f:Number = parseFloat(expr);
			e._call     = function ():Number {return f;};
		} else {
			e._call = e.evalUntil("");
		}

		return e;
	}
	private static function error(src:String, expr:String, msg:String, tail:Boolean = true):Error {
		return new Error("In expr: "+src+"\n"+msg+(tail?": "+expr:""));
	}
	private function evalPostExpr(x:Function,minPrio:int):Function {
		var m:Array;
		var y:Function,z:Function;
		while (true) {
			eatWs();
			if (eatStr('()')) {
				x = wrapCall(x,[]);
			} else if (eatStr('(')) {
				var args:/*Function*/Array = [];
				while(true){
					y = evalExpr(0);
					args.push(y);
					if (eatStr(')')) break;
					if (!eatStr(',')) throw error(_src,expr,"Expected ')' or ','");
				}
				x = wrapCall(x,args);
			} else if (eatStr('.')) {
				m = eat(LA_ID);
				if (!m) throw error(_src,expr,"Identifier expected");
				x = wrapDot(x, wrapVal(m[0]));
			} else if (eatStr('[')) {
				y = evalUntil("]");
				eatWs();
				if (!eatStr(']')) throw error(_src,expr,"Expected ']'");
				x    = wrapDot(x, y);
			} else if (eatStr('?')) {
				y = evalUntil(':');
				if (!eatStr(':')) throw error(_src,expr,"Expected ':'");
				z = evalExpr(0);
				x = wrapIf(x, y, z);
			} else if ((m = eat(LA_OPERATOR))) {
				var p:int = OP_PRIORITIES[m[0]];
				if (p>minPrio) {
					y = evalExpr(p);
					x = wrapOp(x, m[0], y);
				} else {
					unshift(m[0]);
					break;
				}
			} else break;
		}
		eatWs();
		return x;
	}
	public static function calculateOp(x:*,op:String,y:*):* {
		switch (op) {
			case '>':
			case 'gt':
				return x > y;
			case '>=':
			case 'gte':
			case 'ge':
				return x >= y;
			case '<':
			case 'lt':
				return x < y;
			case '<=':
			case 'lte':
			case 'le':
				return x <= y;
			case '=':
			case '==':
			case 'eq':
				return x == y;
			case '===':
				return x === y;
			case '!=':
			case 'ne':
			case 'neq':
				return x != y;
			case '!==':
				return x !== y;
			case '+':
				return x + y;
			case '-':
				return x - y;
			case '%':
				return x % y;
			case '*':
				return x * y;
			case '/':
				return x / y;
			case '||':
			case 'or':
				return x || y;
			case '&&':
			case 'and':
				return x && y;
			default:
				throw new Error("Unregistered operator " + op);
		}
	}
	private function calculate(x:Function, op:String, y:Function):* {
//		trace("Evaluating " + (typeof x) + " " + x + " " + op + " " + (typeof y) + " " + y);
		switch (op) {
			case '||':
			case 'or':
				return x() || y();
			case '&&':
			case 'and':
				return x() && y();
			default:
				try {
					return calculateOp(x(),op,y());
				} catch (e: Error) {
					throw error(_src, expr, "Unregistered operator " + op, false);
				}
		}
	}
	private function evalExpr(minPrio:int):Function {
		var m:/*String*/Array;
		var x:Function;
		eatWs();
		if (eatStr('(')) {
			x = evalUntil(")");
			eatStr(")");
		} else if (eatStr('!') || eat(/^not\b/)) {
			x = wrapNot(evalExpr(60));
		} else if (eatStr('[')) {
			var f:/*Function*/Array;
			if (eatStr(']')) {
				f = [];
			} else {
				f = [evalExpr(0)];
				while (eatStr(',')) {
					f.push(evalExpr(0));
				}
				if (!eatStr("]")) throw error(_src, expr, "Expected ',' or ']'");
			}
			x = wrapArray(f);
		} else if (eatStr('{')) {
			if (eatStr('}')) {
				f = [];
			} else {
				f = [];
				while (true) {
					eatWs();
					var key:String;
					if ((m = eat(/^['"]/))) {
						var delim:String = m[0];
						key = evalStringLiteral(delim);
					} else if ((m = eat(LA_ID))) {
						key = m[1];
					} else break;
					f.push(wrapVal(key));
					eatWs();
					if (!eatStr(':')) throw error(_src, expr, "Expected ':' after '"+key+"'");
					eatWs();
					f.push(evalExpr(0));
					if (eatStr('}')) break;
					if (!eatStr(',')) throw error(_src, expr, "Expected ',' or '}'");
				}
			}
			x = wrapCall(wrapVal(Utils.createMapFromPairs),f);
		} else if ((m = eat(LA_FLOAT))) {
			x = wrapVal(parseFloat(m[0]));
		} else if ((m = eat(LA_INT))) {
			x = wrapVal(parseInt(m[0]));
		} else if ((m = eat(/^['"]/))) {
			delim = m[0];
			var s:String     = evalStringLiteral(delim);
			x                = wrapVal(s);
		} else if ((m = eat(LA_ID))) {
			x = wrapId(m[0]);
		} else {
			throw error(_src,expr,"Not a sub-expr");
		}
		return evalPostExpr(x,minPrio);
	}
	private function evalStringLiteral(delim:String):String {
		var s:String   = '';
		var m:/*String*/Array;
		var rex:RegExp = delim == '"' ? /^[^"\\]*/ : /^[^'\\]*/;
		while (true) {
			if (eatStr('\\')) {
				var c:String = eatN(1);
				s += {
					     'n': '\n', 't': '\t', 'r': '', '"': '"', "'": "'"
				     }[c] || '';
			} else if (eatStr(delim)) {
				break
			} else if ((m = eat(rex))) {
				s += m[0];
			} else {
				throw error(_src, expr, "Expected text");
			}
		}
		return s;
	}
	private function evalUntil(until:String):* {
		var x:* = evalExpr(0);
		if (expr == until || expr.charAt(0) == until) return x;
		if (until) throw error(_src,expr,"Operator or " + until + "expected");
		throw error(_src,expr,"Operator expected");
	}
	private function eat(rex:RegExp):Array {
		var m:Array = expr.match(rex);
		if (m) eatN(m[0].length);
		return m;
	}
	private function unshift(s:String):void {
		expr = s+expr;
	}
	private function eatN(n:int):String {
		var s:String = expr.substr(0,n);
		expr = expr.substr(n);
		return s;
	}
	private function eatStr(s:String):Boolean {
		if (expr.substr(0,s.length).indexOf(s) == 0) {
			eatN(s.length);
			return true;
		}
		return false;
	}
	private function eatWs():void {
		//noinspection StatementWithEmptyBodyJS
		while (eat(/^\s+/) || eat(LA_BLOCK_COMMENT)){}
	}
	private function evalId(id:String):* {
		switch (id) {
			case 'Math': return Math;
			case 'undefined': return undefined;
			case 'null': return null;
			case 'int': return int;
			case 'uint': return uint;
			case 'String': return String;
			case 'string': return String;
			case 'Number': return Number;
			case 'true': return true;
			case 'false': return false;
			default:
				for each (var thiz:* in scopes) if (id in thiz) return thiz[id];
				return undefined;
		}
	}
	private function wrapId(id:String):Function {
		return function():*{ return evalId(id); };
	}
	private function evalDot(obj:Object,key:String):* {
		if (!(key in obj)) return undefined;
		var y:* = obj[key];
		if (y is Function) {
			y = Utils.bindThis(y,obj);
		}
		return y;
	}

	private function wrapVal(x:*):Function {
		return function ():* { return x; };
	}
	/**
	 * @param fn ()=>( (args)=>any )
	 * @param args (()=>arg)[]
	 */
	private function wrapCall(fn:Function,args:/*Function*/Array):Function {
		return function ():* {
			var a:Array = [];
			for (var i:int = 0, n:int = args.length; i < n; i++) a[i] = args[i]();
			return (fn() as Function).apply(null, a);
		};
	}
	private function wrapIf(condition:Function,then:Function,elze:Function):Function {
		return functionIf(condition,then,elze);
	}
	private function wrapDot(obj:Function,index:Function):Function {
		return function():* {
			return evalDot(obj(),index());
		};
	}
	private function wrapOp(x:Function,op:String,y:Function):Function {
		return function():* {
			return calculate(x,op,y);
		};
	}
	private function wrapNot(x:Function):Function {
		return function():* {
			return !x();
		};
	}
	private function wrapArray(array:/*Function*/Array):Function {
		return function():Array {
			return array.map(function (el:Function,id:int,arr:Array):* {
				return el();
			})
		};
	}

	public static function escapeString(s:String):String {
		return s.replace(/\n/g,'\n').replace(/\r/g,'\r').replace(/'/g,"\\'").replace(/"/g,'\\"').replace(/\\/g,'\\\\');
	}
}
}


code:
/**
 * Coded by aimozg on 04.06.2017.
 */
package coc.view {
import classes.internals.LoggerFactory;
import classes.internals.Utils;

import flash.display.Bitmap;
import flash.display.Sprite;
import flash.geom.Matrix;

import mx.logging.ILogger;

[Style(name="fillColor", type="uint", format="Color", inherit="no")]
public class BitmapDataSprite extends Sprite {
	private static const LOGGER:ILogger = LoggerFactory.getLogger(BitmapDataSprite);
	public function BitmapDataSprite(options:Object = null) {
		super();
		options = Utils.extend({},options);
		if (options) {
			_fillColor = UIUtils.convertColor(Utils.moveValue(options,'fillColor',_fillColor));
			_width = Utils.moveValue(options,'width',_width);
			_height = Utils.moveValue(options,'height',_height);
			if (_width || _height) setSize(_width,_height);
			_stretch = Utils.moveValue(options,'stretch',_stretch);
			_repeat = Utils.moveValue(options,'repeat',_repeat);
			bitmapClass = Utils.moveValue(options,'bitmapClass',null);
			bitmap = Utils.moveValue(options,'bitmap',_bitmap);
			for (var key:String in options) {
			if (options.hasOwnProperty(key)) {
				var value:* = options[key];
						if (key in this) {
							this[key] = value;
						} else {
							LOGGER.warn("Unknown BitmapDataSprite property", key)
						}
				}
			}
		}
	}
	private var _bitmap:Bitmap   = null;
	private var _fillColor:uint  = 0;
	private var _width:Number    = 0;
	private var _height:Number   = 0;
	private var _stretch:Boolean = false;
	private var _repeat:Boolean  = false;
	public function set bitmapClass(value:Class):void {
		if (value as Class) bitmap = (new value()) as Bitmap;
		else bitmap = null;
	}
	public function get bitmapClass():Class {
		return null;
	}
	public function get bitmap():Bitmap {
		return _bitmap;
	}
	public function set bitmap(value:Bitmap):void {
		if (_bitmap == value) return;
		_bitmap = value;
		if (value) {
			if (_width == 0 || !stretch && !repeat) _width = value.width;
			if (_height == 0 || !stretch && !repeat) _height = value.height;
		}
		redraw();
	}
	public function get fillColor():uint {
		return _fillColor;
	}
	public function set fillColor(value:uint):void {
		if (_fillColor == value) return;
		_fillColor = value;
		redraw();
	}
	override public function set width(value:Number):void {
		setSize(value,_height);
	}
	override public function set height(value:Number):void {
		setSize(_width,value);
	}
	public function setSize(width:Number, height:Number):void {
		_width = width;
		_height = height;
		redraw();
		super.width = width;
		super.height = height;
	}
	public function get stretch():Boolean {
		return _stretch;
	}
	public function set stretch(value:Boolean):void {
		if (_stretch == value) return;
		_stretch = value;
		redraw();
	}
	public function get repeat():Boolean {
		return _repeat;
	}
	public function set repeat(value:Boolean):void {
		if (_repeat == value) return;
		_repeat = value;
		redraw();
	}
	private function redraw():void {
		this.graphics.clear();
		if (bitmap) {
			if (stretch) {
				var m:Matrix = new Matrix();
				m.scale(_width / bitmap.width, _height / bitmap.height);
				this.graphics.beginBitmapFill(bitmap.bitmapData, m, false, true);
			} else {
				this.graphics.beginBitmapFill(bitmap.bitmapData, null, repeat);
			}
			this.graphics.drawRect(0, 0, _width, _height);
			this.graphics.endFill();
		} else {
			this.graphics.beginFill(_fillColor, 1.0);
			this.graphics.drawRect(0, 0, _width, _height);
			this.graphics.endFill();
		}
	}
}
}