code:
/**
 * Created by aimozg on 12.01.14.
 */
package classes.Scenes
{
	import classes.*;
	import classes.GlobalFlags.kFLAGS;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.Items.Armor;
	import classes.Items.Useable;
	import classes.Items.Weapon;
	import classes.Items.Jewelry;
	import classes.Items.Shield;
	import classes.Items.Undergarment;
	import classes.Items.ArmorLib;
	import classes.Items.WeaponLib;
	import classes.Items.JewelryLib;
	import classes.Items.ShieldLib;
	import classes.Items.UndergarmentLib;
	import classes.Scenes.Dungeons.DungeonCore;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;

	use namespace kGAMECLASS;

	public class Inventory extends BaseContent {
		private static const inventorySlotName:Array = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth"];

		private var itemStorage:Array;
		private var gearStorage:Array;
		private var prisonStorage:Array;
		private var callNext:Function;		//These are used so that we know what has to happen once the player finishes with an item
		private var callOnAbandon:Function;	//They simplify dealing with items that have a sub menu. Set in inventoryMenu and in takeItem
		private var currentItemSlot:ItemSlotClass;	//The slot previously occupied by the current item - only needed for stashes and items with a sub menu.

		public function Inventory(saveSystem:Saves) {
			itemStorage = [];
			gearStorage = [];
			prisonStorage = [];
			saveSystem.linkToInventory(itemStorageDirectGet, gearStorageDirectGet);
		}

		public function showStash():Boolean {
			return player.hasKeyItem("Equipment Rack - Weapons") >= 0 || player.hasKeyItem("Equipment Rack - Armor") >= 0 || itemStorage.length > 0 || flags[kFLAGS.ANEMONE_KID] > 0 || player.hasKeyItem("Equipment Storage - Jewelry Box") >= 0 || flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER] > 0;
		}

		public function itemStorageDirectGet():Array { return itemStorage; }

		public function gearStorageDirectGet():Array { return gearStorage; }

		public function prisonStorageDirectGet():Array { return prisonStorage; }

//		public function currentCallNext():Function { return callNext; }

		public function itemGoNext():void { if (callNext != null) doNext(callNext); }

		public function inventoryMenu():void {
			var x:int;
			var foundItem:Boolean = false;
			if (getGame().inCombat) {
				callNext = inventoryCombatHandler; //Player will return to combat after item use
			}
			else {
				spriteSelect(-1);
				callNext = inventoryMenu; //In camp or in a dungeon player will return to inventory menu after item use
			}
			hideMenus();
			hideUpDown();
			clearOutput();
			kGAMECLASS.displayHeader("Inventory");
			outputText("Equipment:\n");
			outputText("Weapon: " + player.weapon.name + " (Attack: " + player.weaponAttack + ")\n");
			outputText("Shield: " + player.shield.name + " (Block Rating: " + player.shieldBlock + ")\n");
			outputText("Armour: " + player.armor.name + " (Defense: " + player.armorDef + ")\n");
			outputText("Upper underwear: " + player.upperGarment.name + "\n");
			outputText("Lower underwear: " + player.lowerGarment.name + "\n");
			outputText("Accessory: " + player.jewelryName + "\n");
			if (player.keyItems.length > 0) outputText("\nKey Items:\n");
			for (x = 0; x < player.keyItems.length; x++) outputText(player.keyItems[x].keyName + "\n");
			menu();
			for (x = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked && player.itemSlots[x].quantity > 0) {
					addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), useItemInInventory, x);
					foundItem = true;
				}
			}
			if (!getGame().inCombat) {
				addButton(10, "Unequip", manageEquipment);
			}
			if (!getGame().inCombat && inDungeon == false && inRoomedDungeon == false && flags[kFLAGS.IN_PRISON] == 0 && flags[kFLAGS.IN_INGNAM] == 0 && checkKeyItems(true)) {
				addButton(12, "Key Items", checkKeyItems);
				foundItem = true;
			}
			if (!foundItem) {
				outputText("\nYou have no usable items.");
				doNext(playerMenu);
				if (!getGame().inCombat) {
					addButton(10, "Unequip", manageEquipment);
				}
				return;
			}
			if (getGame().inCombat && player.findStatusEffect(StatusEffects.Sealed) >= 0 && player.statusEffectv1(StatusEffects.Sealed) == 3) {
				outputText("\nYou reach for your items, but you just can't get your pouches open.  Your ability to use items was sealed, and now you've wasted a chance to attack!\n\n");
				monster.doAI();
				return;
			}
			outputText("\nWhich item will you use? (To discard unwanted items, hold Shift then click the item.)");
			outputText("\nCapacity: " + getOccupiedSlots() + " / " + getMaxSlots());
			if (getGame().inCombat)
				addButton(14, "Back", combat.combatMenu, false); //Player returns to the combat menu on cancel
			else
				addButton(14, "Back", playerMenu);
		}

		public function stash():void {
			/*Hacked in cheat to enable shit
			flags[kFLAGS.UNKNOWN_FLAG_NUMBER_00254] = 1;
			flags[kFLAGS.UNKNOWN_FLAG_NUMBER_00255] = 1;*/
			//REMOVE THE ABOVE BEFORE RELASE ()
			hideMenus();
			clearOutput();
			spriteSelect(-1);
			menu();
			if (flags[kFLAGS.ANEMONE_KID] > 0) {
				kGAMECLASS.anemoneScene.anemoneBarrelDescription();
				if (model.time.hours >= 6) addButton(4, "Anemone", kGAMECLASS.anemoneScene.approachAnemoneBarrel);
			}
			if (player.hasKeyItem("Camp - Chest") >= 0 || player.hasKeyItem("Camp - Murky Chest") >= 0 || player.hasKeyItem("Camp - Ornate Chest") >= 0) {
				var chestArray:Array = [];
				if (player.hasKeyItem("Camp - Chest") >= 0) chestArray.push("a large wood and iron chest");
				if (player.hasKeyItem("Camp - Murky Chest") >= 0) chestArray.push("a medium damp chest");
				if (player.hasKeyItem("Camp - Ornate Chest") >= 0) chestArray.push("a medium gilded chest");
				outputText("You have " + formatStringArray(chestArray) + " to help store excess items located ");
				if (camp.homeDesc() == "cabin") outputText("inside your cabin");
				else outputText("near the portal entrance");
				outputText(".\n\n");
				addButton(0, "Chest Store", pickItemToPlaceInCampStorage);
				if (hasItemsInStorage()) addButton(1, "Chest Take", pickItemToTakeFromCampStorage);
			}
			//Weapon Rack
			if (player.hasKeyItem("Equipment Rack - Weapons") >= 0) {
				outputText("There's a weapon rack set up here, set up to hold up to nine various weapons.");
				addButton(2, "W.Rack Put", pickItemToPlaceInWeaponRack);
				if (weaponRackDescription()) addButton(3, "W.Rack Take", pickItemToTakeFromWeaponRack);
				outputText("\n\n");
			}
			//Armor Rack
			if (player.hasKeyItem("Equipment Rack - Armor") >= 0) {
				outputText("Your camp has an armor rack set up to hold your various sets of gear.  It appears to be able to hold nine different types of armor.");
				addButton(5, "A.Rack Put", pickItemToPlaceInArmorRack);
				if (armorRackDescription()) addButton(6, "A.Rack Take", pickItemToTakeFromArmorRack);
				outputText("\n\n");
			}
			//Shield Rack
			if (player.hasKeyItem("Equipment Rack - Shields") >= 0) {
				outputText("There's a shield rack set up here, set up to hold up to nine various shields.");
				addButton(7, "S.Rack Put", pickItemToPlaceInShieldRack);
				if (shieldRackDescription()) addButton(8, "S.Rack Take", pickItemToTakeFromShieldRack);
				outputText("\n\n");
			}
			//Jewelry box
			if (player.hasKeyItem("Equipment Storage - Jewelry Box") >= 0) {
				outputText("Your jewelry box is located ");
				if (flags[kFLAGS.CAMP_BUILT_CABIN] > 0 && flags[kFLAGS.CAMP_CABIN_FURNITURE_BED])
				{
					if (flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER]) outputText("on your dresser inside your cabin.");
					else
					{
						if (flags[kFLAGS.CAMP_CABIN_FURNITURE_NIGHTSTAND]) outputText("on your nightstand inside your cabin.");
						else  outputText("under your bed inside your cabin.");
					}
				}
				else outputText("next to your bedroll.");
				addButton(10, "J.Box Put", inventory.pickItemToPlaceInJewelryBox);
				if (inventory.jewelryBoxDescription()) addButton(11, "J.Box Take", inventory.pickItemToTakeFromJewelryBox);
				outputText("\n\n", false);
			}
			//Dresser
			if (flags[kFLAGS.CAMP_CABIN_FURNITURE_DRESSER] > 0) {
				outputText("You have a dresser inside your cabin to store nine different types of undergarments.");
				addButton(12, "Dresser Put", inventory.pickItemToPlaceInDresser);
				if (inventory.dresserDescription()) addButton(13, "Dresser Take", inventory.pickItemToTakeFromDresser);
				outputText("\n\n");
			}
			addButton(14, "Back", playerMenu);
		}

		public function takeItem(itype:ItemType, nextAction:Function, overrideAbandon:Function = null, source:ItemSlotClass = null):void {
			if (itype == null) {
				CoC_Settings.error("takeItem(null)");
				return;
			}
			if (itype == ItemType.NOTHING) return;
			if (nextAction != null)
				callNext = nextAction;
			else callNext = playerMenu;
			//Check for an existing stack with room in the inventory and return the value for it.
			var temp:int = player.roomInExistingStack(itype);
			if (temp >= 0) { //First slot go!
				player.itemSlots[temp].quantity++;
				outputText("You place " + itype.longName + " in your " + inventorySlotName[temp] + " pouch, giving you " + player.itemSlots[temp].quantity + " of them.");
				itemGoNext();
				return;
			}
			//If not done, then put it in an empty spot!
			//Throw in slot 1 if there is room
			temp = player.emptySlot();
			if (temp >= 0) {
				player.itemSlots[temp].setItemAndQty(itype, 1);
				outputText("You place " + itype.longName + " in your " + inventorySlotName[temp] + " pouch.");
				itemGoNext();
				return;
			}
			if (overrideAbandon != null) //callOnAbandon only becomes important if the inventory is full
				callOnAbandon = overrideAbandon;
			else callOnAbandon = callNext;
			//OH NOES! No room! Call replacer functions!
			takeItemFull(itype, true, source);
		}

		public function returnItemToInventory(item:Useable, showNext:Boolean = true):void { //Used only by items that have a sub menu if the player cancels
			if (!debug) {
				if (currentItemSlot == null) {
					takeItem(item, callNext, callNext, null); //Give player another chance to put item in inventory
				}
				else if (currentItemSlot.quantity > 0) { //Add it back to the existing stack
					currentItemSlot.quantity++;
				}
				else { //Put it back in the slot it came from
					currentItemSlot.setItemAndQty(item, 1);
				}
			}
			if (getGame().inCombat) {
				monster.doAI();
				return;
			}
			if (showNext)
				doNext(callNext); //Items with sub menus should return to the inventory screen if the player decides not to use them
			else callNext(); //When putting items back in your stash we should skip to the take from stash menu
		}

		//Check to see if anything is stored
		public function hasItemsInStorage():Boolean { return itemAnyInStorage(itemStorage, 0, itemStorage.length); }

		public function hasItemInStorage(itype:ItemType):Boolean { return itemTypeInStorage(itemStorage, 0, itemStorage.length, itype); }

		public function consumeItemInStorage(itype:ItemType):Boolean {
			temp = itemStorage.length;
			while(temp > 0) {
				temp--;
				if (itemStorage[temp].itype == itype && itemStorage[temp].quantity > 0) {
					itemStorage[temp].quantity--;
					return true;
				}
			}
			return false;
		}

		public function giveHumanizer():void {
			if (flags[kFLAGS.TIMES_CHEATED_COUNTER] > 0) {
				outputText("I was a cheater until I took an arrow to the knee...", true);
				getGame().gameOver();
				return;
			}
			outputText("I AM NOT A CROOK.  BUT YOU ARE!  CHEATER!\n\n", true);
			inventory.takeItem(consumables.HUMMUS_, playerMenu);
			flags[kFLAGS.TIMES_CHEATED_COUNTER]++;
		}

		public function getMaxSlots():int {
			var slots:int = 3;
			if (player.findPerk(PerkLib.StrongBack) >= 0) slots++;
			if (player.findPerk(PerkLib.StrongBack2) >= 0) slots++;
			slots += player.keyItemv1("Backpack");
			//Constrain slots to between 3 and 10.
			if (slots < 3) slots = 3;
			if (slots > 10) slots = 10;
			return slots;
		}
		public function getOccupiedSlots():int {
			var occupiedSlots:int = 0;
		    for (var i:int = 0; i < player.itemSlots.length; i++) {
				if (!player.itemSlot(i).isEmpty() && player.itemSlot(i).unlocked) occupiedSlots++;
			}
			return occupiedSlots;
		}

		//Create a storage slot
		public function createStorage():Boolean {
			if (itemStorage.length >= 16) return false;
			var newSlot:ItemSlotClass = new ItemSlotClass();
			itemStorage.push(newSlot);
			return true;
		}

		//Clear storage slots
		public function clearStorage():void {
			//Various Errors preventing action
			if (itemStorage == null) trace("ERROR: Cannot clear storage because storage does not exist.");
			else {
				trace("Attempted to remove " + itemStorage.length + " storage slots.");
				itemStorage.splice(0, itemStorage.length);
			}
		}

		public function clearGearStorage():void {
			//Various Errors preventing action
			if (gearStorage == null) trace("ERROR: Cannot clear storage because storage does not exist.");
			else {
				trace("Attempted to remove " + gearStorage.length + " storage slots.");
				gearStorage.splice(0, gearStorage.length);
			}
		}

		public function initializeGearStorage():void {
			//Completely empty storage array
			if (gearStorage == null) trace("ERROR: Cannot clear gearStorage because storage does not exist.");
			else {
				trace("Attempted to remove " + gearStorage.length + " gearStorage slots.");
				gearStorage.splice(0, gearStorage.length);
			}
			//Rebuild a new one!
			var newSlot:ItemSlotClass;
			while (gearStorage.length < 45) {
				newSlot = new ItemSlotClass();
				gearStorage.push(newSlot);
			}
		}

		private function useItemInInventory(slotNum:int):void {
			clearOutput();
			if (player.itemSlots[slotNum].itype is Useable) {
				var item:Useable = player.itemSlots[slotNum].itype as Useable;
				if (flags[kFLAGS.SHIFT_KEY_DOWN] == 1) {
					deleteItemPrompt(item, slotNum);
					return;
				}
				if (item.canUse()) { //If an item cannot be used then canUse should provide a description of why the item cannot be used
					if (!debug) player.itemSlots[slotNum].removeOneItem();
					useItem(item, player.itemSlots[slotNum]);
					return;
				}
			}
			else {
				outputText("You cannot use " + player.itemSlots[slotNum].itype.longName + "!\n\n");
			}
			itemGoNext(); //Normally returns to the inventory menu. In combat it goes to the inventoryCombatHandler function
/* menuLoc is no longer needed, after monster.doAI game will always move to the next round
			else if (menuLoc == 1) {
				menuLoc = 0;
				if (!combatRoundOver()) {
					outputText("\n\n");
					monster.doAI();
				}
			}
*/
		}

		private function inventoryCombatHandler():void {
			if (!combat.combatRoundOver()) { //Check if the battle is over. If not then go to the enemy's action.
				outputText("\n\n");
				monster.doAI();
			}
		}
		private function deleteItemPrompt(item:Useable, slotNum:int):void {
			clearOutput();
			outputText("Are you sure you want to destroy " + player.itemSlots[slotNum].quantity + "x " + item.shortName + "?  You won't be able to retrieve " + (player.itemSlots[slotNum].quantity == 1 ? "it": "them") + "!");
			menu();
			addButton(0, "Yes", deleteItem, item, slotNum);
			addButton(1, "No", inventoryMenu);
			//doYesNo(deleteItem, inventoryMenu);
		}

		private function deleteItem(item:Useable, slotNum:int):void {
			clearOutput();
			outputText(player.itemSlots[slotNum].quantity + "x " + item.shortName + " " + (player.itemSlots[slotNum].quantity == 1 ? "has": "have") + " been destroyed.");
			player.destroyItems(item, player.itemSlots[slotNum].quantity);
			doNext(inventoryMenu);
		}

		private function useItem(item:Useable, fromSlot:ItemSlotClass):void {
			item.useText();
			if (item is Armor) {
				player.armor.removeText();
				item = player.setArmor(item as Armor); //Item is now the player's old armor
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Weapon) {
				player.weapon.removeText();
				item = player.setWeapon(item as Weapon); //Item is now the player's old weapon
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Jewelry) {
				player.jewelry.removeText();
				item = player.setJewelry(item as Jewelry); //Item is now the player's old jewelry
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Shield) {
				player.shield.removeText();
				item = player.setShield(item as Shield); //Item is now the player's old shield
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else if (item is Undergarment) {
				if (item["type"] == 0) player.upperGarment.removeText();
				else player.lowerGarment.removeText();
				item = player.setUndergarment(item as Undergarment, item["type"]); //Item is now the player's old shield
				if (item == null)
					itemGoNext();
				else takeItem(item, callNext);
			}
			else {
				currentItemSlot = fromSlot;
				if (!item.useItem()) itemGoNext(); //Items should return true if they have provided some form of sub-menu.
					//This is used for Reducto and GroPlus (which always present the player with a sub-menu)
					//and for the Kitsune Gift (which may show a sub-menu if the player has a full inventory)
//				if (!item.hasSubMenu()) itemGoNext(); //Don't call itemGoNext if there's a sub menu, otherwise it would never be displayed
			}
		}

		private function takeItemFull(itype:ItemType, showUseNow:Boolean, source:ItemSlotClass):void {
			outputText("There is no room for " + itype.longName + " in your inventory.  You may replace the contents of a pouch with " + itype.longName + " or abandon it.");
			menu();
			for (var x:int = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked)
					addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), createCallBackFunction2(replaceItem, itype, x));
			}
			if (source != null) {
				currentItemSlot = source;
				addButton(12, "Put Back", createCallBackFunction2(returnItemToInventory, itype, false));
			}
			if (showUseNow && itype is Useable) addButton(13, "Use Now", createCallBackFunction2(useItemNow, itype as Useable, source));
			addButton(14, "Abandon", callOnAbandon); //Does not doNext - immediately executes the callOnAbandon function
		}

		private function useItemNow(item:Useable, source:ItemSlotClass):void {
			clearOutput();
			if (item.canUse()) { //If an item cannot be used then canUse should provide a description of why the item cannot be used
				useItem(item, source);
			}
			else {
				takeItemFull(item, false, source); //Give the player another chance to take this item
			}
		}

		private function replaceItem(itype:ItemType, slotNum:int):void {
			clearOutput();
			if (player.itemSlots[slotNum].itype == itype) //If it is the same as what's in the slot...just throw away the new item
				outputText("You discard " + itype.longName + " from the stack to make room for the new one.");
			else { //If they are different...
				if (player.itemSlots[slotNum].quantity == 1) outputText("You throw away " + player.itemSlots[slotNum].itype.longName + " and replace it with " + itype.longName + ".");
				else outputText("You throw away " + player.itemSlots[slotNum].itype.longName + "(x" + player.itemSlots[slotNum].quantity + ") and replace it with " + itype.longName + ".");
				player.itemSlots[slotNum].setItemAndQty(itype, 1);
			}
			itemGoNext();
		}

		//My unequip function is still superior, albeit rewritten.
		//private function unequipWeapon():void {
		//	clearOutput();
		//	takeItem(player.setWeapon(WeaponLib.FISTS), inventoryMenu);
		//}

/* Never called
		public function hasItemsInRacks(itype:ItemType, armor:Boolean):Boolean {
			if (armor) return itemTypeInStorage(gearStorage, 9, 18, itype);
			return itemTypeInStorage(gearStorage, 0, 9, itype);
		}
*/

		public function armorRackDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 9, 18)) {
				var itemList:Array = [];
				for (var x:int = 9; x < 18; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function weaponRackDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 0, 9)) {
				var itemList:Array = [];
				for (var x:int = 0; x < 9; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function shieldRackDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 36, 45)) {
				var itemList:Array = [];
				for (var x:int = 36; x < 45; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function jewelryBoxDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 18, 27)) {
				var itemList:Array = [];
				for (var x:int = 18; x < 27; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		public function dresserDescription():Boolean {
			if (itemAnyInStorage(gearStorage, 27, 36)) {
				var itemList:Array = [];
				for (var x:int = 27; x < 36; x++)
					if (gearStorage[x].quantity > 0) itemList[itemList.length] = gearStorage[x].itype.longName;
				outputText("  It currently holds " + formatStringArray(itemList) + ".");
				return true;
			}
			return false;
		}

		private function itemAnyInStorage(storage:Array, startSlot:int, endSlot:int):Boolean {
			for (var x:int = startSlot; x < endSlot; x++) {
				if (storage[x] != undefined) if (storage[x].quantity > 0) return true;
			}
			return false;
		}

		private function itemTypeInStorage(storage:Array, startSlot:int, endSlot:int, itype:ItemType):Boolean {
			for (var x:int = startSlot; x < endSlot; x++) {
				if (storage[x] != undefined) if (storage[x].quantity > 0 && storage[x].itype == itype) return true;
			}
			return false;
		}

		public function removeItemFromStorage(storage:Array, itype:ItemType):void {
			for (var x:int = 0; x < storage.length; x++) {
				if (storage[x] != undefined) {
					if (storage[x].quantity > 0 && storage[x].itype == itype) {
						storage[x].quantity--;
						return;
					}
				}
			}
		}

		private function pickItemToTakeFromCampStorage():void {
			callNext = pickItemToTakeFromCampStorage;
			pickItemToTakeFromStorage(itemStorage, 0, itemStorage.length, "storage");
		}

		public function manageEquipment():void {
			clearOutput();
			outputText("Which would you like to unequip?\n\n");
			menu();
			if (player.weapon != WeaponLib.FISTS)
			{
				addButton(0, "Weapon", unequipWeapon, null, null, null, player.weapon.description, capitalizeFirstLetter(player.weapon.name));
			}
			if (player.shield != ShieldLib.NOTHING)
			{
				addButton(1, "Shield", unequipShield, null, null, null, player.shield.description, capitalizeFirstLetter(player.shield.name));
			}
			if (player.jewelry != JewelryLib.NOTHING)
			{
				addButton(2, "Accessory", unequipJewel, null, null, null, player.jewelry.description, capitalizeFirstLetter(player.jewelry.name));
			}
			if (player.armor != ArmorLib.NOTHING)
			{
				addButton(5, "Armour", unequipArmor, null, null, null, player.armor.description, capitalizeFirstLetter(player.armor.name));
			}
			if (player.upperGarment != UndergarmentLib.NOTHING)
			{
				addButton(6, "Upperwear", unequipUpperwear, null, null, null, player.upperGarment.description, capitalizeFirstLetter(player.upperGarment.name));
			}
			if (player.lowerGarment != UndergarmentLib.NOTHING)
			{
				addButton(7, "Lowerwear", unequipLowerwear, null, null, null, player.lowerGarment.description, capitalizeFirstLetter(player.lowerGarment.name));
			}
			addButton(14, "Back", inventoryMenu);

		}
		//Unequip!
		private function unequipWeapon():void {
			takeItem(player.setWeapon(WeaponLib.FISTS), inventoryMenu);
		}
		public function unequipArmor():void {
			if (player.armorName != "goo armor") takeItem(player.setArmor(ArmorLib.NOTHING), inventoryMenu);
			else { //Valeria belongs in the camp, not in your inventory!
				player.armor.removeText();
				player.setArmor(ArmorLib.NOTHING);
				doNext(manageEquipment);
			}
		}
		public function unequipUpperwear():void {
			takeItem(player.setUndergarment(UndergarmentLib.NOTHING, UndergarmentLib.TYPE_UPPERWEAR), inventoryMenu);
		}
		public function unequipLowerwear():void {
			takeItem(player.setUndergarment(UndergarmentLib.NOTHING, UndergarmentLib.TYPE_LOWERWEAR), inventoryMenu);
		}
		public function unequipJewel():void {
			takeItem(player.setJewelry(JewelryLib.NOTHING), inventoryMenu);
		}
		public function unequipShield():void {
			takeItem(player.setShield(ShieldLib.NOTHING), inventoryMenu);
		}

		public function checkKeyItems(countOnly:Boolean = false):Boolean {
			var foundItem:Boolean = false
			var button:int = 0;
			if (!countOnly) menu();
			if (getGame().xmas.xmasMisc.nieveHoliday() && flags[kFLAGS.NIEVE_STAGE] > 0 && flags[kFLAGS.NIEVE_STAGE] < 5) {
				if (!countOnly) {
					if (flags[kFLAGS.NIEVE_STAGE] == 1)
						outputText("\nThere's some odd snow here that you could do something with...\n");
					else
						outputText("\nYou have a snow" + getGame().xmas.xmasMisc.nieveMF("man", "woman") + " here that seems like it could use a little something...\n");
					addButton(button++, "Snow", getGame().xmas.xmasMisc.nieveBuilding);
				}
				foundItem = true;
			}
			if (flags[kFLAGS.FUCK_FLOWER_KILLED] == 0 && flags[kFLAGS.FUCK_FLOWER_LEVEL] >= 1) {
				if (!countOnly) {
					if (flags[kFLAGS.FUCK_FLOWER_LEVEL] == 4) outputText("\nHolli is in her tree at the edges of your camp.  You could go visit her if you want.\n");
					addButton(button++, (flags[kFLAGS.FUCK_FLOWER_LEVEL] >= 3 ? "Tree" : "Plant"), getGame().holliScene.treeMenu);
				}
				foundItem = true;
			}
			if (player.hasKeyItem("Dragon Egg") >= 0) {
				if (!countOnly) {
					getGame().emberScene.emberCampDesc();
					addButton(button++, "Egg", getGame().emberScene.emberEggInteraction);
				}
				foundItem = true;
			}
			if (player.hasKeyItem("Tamani's Satchel") >= 0) {
				if (!countOnly) {
					addButton(button++, "Satchel", getGame().forest.tamaniScene.openTamanisSatchel);
				}
				foundItem = true;
			}
			if (player.hasKeyItem("Feathery hair-pin") >= 0) {
				if (!countOnly) {
					var benoitPinDesc:String;
					benoitPinDesc = "The feathery hair-pin " + getGame().bazaar.benoit.benoitMF("Benoit", "Benoite") + " gave to you as a present.";
					addButton(button++, "F. Hairpin", getGame().bazaar.benoit.equipUnequipHairPin, null, null, null, benoitPinDesc, "Feathery Hair-pin");
				}
				foundItem = true;
			}
			if (!countOnly) addButton(14, "Back", inventoryMenu);
			return foundItem;
		}

		//Pick item to take from storage
		private function pickItemToTakeFromShieldRack():void {
			callNext = pickItemToTakeFromShieldRack;
			pickItemToTakeFromStorage(gearStorage, 36, 45, "rack");
		}

		private function pickItemToTakeFromArmorRack():void {
			callNext = pickItemToTakeFromArmorRack;
			pickItemToTakeFromStorage(gearStorage, 9, 18, "rack");
		}

		private function pickItemToTakeFromWeaponRack():void {
			callNext = pickItemToTakeFromWeaponRack;
			pickItemToTakeFromStorage(gearStorage, 0, 9, "rack");
		}

		public function pickItemToTakeFromJewelryBox():void {
			callNext = pickItemToTakeFromJewelryBox;
			pickItemToTakeFromStorage(gearStorage, 18, 27, "box");
		}

		public function pickItemToTakeFromDresser():void {
			callNext = pickItemToTakeFromDresser;
			pickItemToTakeFromStorage(gearStorage, 27, 36, "dresser");
		}

		private function pickItemToTakeFromStorage(storage:Array, startSlot:int, endSlot:int, text:String):void {
			clearOutput(); //Selects an item from a gear slot. Rewritten so that it no longer needs to use numbered events
			hideUpDown();
			if (!itemAnyInStorage(storage, startSlot, endSlot)) { //If no items are left then return to the camp menu. Can only happen if the player removes the last item.
				playerMenu();
				return;
			}
			outputText("What " + text + " slot do you wish to take an item from?");
			var button:int = 0;
			menu();
			for (var x:int = startSlot; x < endSlot; x++, button++) {
				if (storage[x].quantity > 0) addButton(button, (storage[x].itype.shortName + " x" + storage[x].quantity), createCallBackFunction2(pickFrom, storage, x));
			}
			addButton(14, "Back", stash);
		}

		private function pickFrom(storage:Array, slotNum:int):void {
			clearOutput();
			var itype:ItemType = storage[slotNum].itype;
			storage[slotNum].quantity--;
			inventory.takeItem(itype, callNext, callNext, storage[slotNum]);
		}

		//Pick items to place in storage
		private function pickItemToPlaceInCampStorage():void { pickItemToPlaceInStorage(placeInCampStorage, allAcceptable, "storage containers", false); }

		private function pickItemToPlaceInArmorRack():void { pickItemToPlaceInStorage(placeInArmorRack, armorAcceptable, "armor rack", true); }

		private function pickItemToPlaceInWeaponRack():void { pickItemToPlaceInStorage(placeInWeaponRack, weaponAcceptable, "weapon rack", true); }

		private function pickItemToPlaceInShieldRack():void { pickItemToPlaceInStorage(placeInShieldRack, shieldAcceptable, "shield rack", true); }

		public function pickItemToPlaceInJewelryBox():void { pickItemToPlaceInStorage(placeInJewelryBox, jewelryAcceptable, "jewelry box", true); }

		public function pickItemToPlaceInDresser():void { pickItemToPlaceInStorage(placeInDresser, undergarmentAcceptable, "dresser", true); }

		//Acceptable type of items
		private function allAcceptable(itype:ItemType):Boolean { return true; }

		private function armorAcceptable(itype:ItemType):Boolean { return itype is Armor; }

		private function weaponAcceptable(itype:ItemType):Boolean { return itype is Weapon; }

		private function shieldAcceptable(itype:ItemType):Boolean { return itype is Shield; }

		private function jewelryAcceptable(itype:ItemType):Boolean { return itype is Jewelry; }

		private function undergarmentAcceptable(itype:ItemType):Boolean { return itype is Undergarment; }

		//Place in storage functions
		private function pickItemToPlaceInStorage(placeInStorageFunction:Function, typeAcceptableFunction:Function, text:String, showEmptyWarning:Boolean):void {
			clearOutput(); //Selects an item to place in a gear slot. Rewritten so that it no longer needs to use numbered events
			hideUpDown();
			outputText("What item slot do you wish to empty into your " + text + "?");
			menu();
			var foundItem:Boolean = false;
			for (var x:int = 0; x < 10; x++) {
				if (player.itemSlots[x].unlocked && player.itemSlots[x].quantity > 0 && typeAcceptableFunction(player.itemSlots[x].itype)) {
					addButton(x, (player.itemSlots[x].itype.shortName + " x" + player.itemSlots[x].quantity), placeInStorageFunction, x);
					foundItem = true;
				}
			}
			if (showEmptyWarning && !foundItem) outputText("\nYou have no appropriate items to put in this " + text + ".");
			addButton(14, "Back", stash);
		}

		private function placeInCampStorage(slotNum:int):void {
			placeIn(itemStorage, 0, itemStorage.length, slotNum);
			doNext(pickItemToPlaceInCampStorage);
		}

		private function placeInArmorRack(slotNum:int):void {
			placeIn(gearStorage, 9, 18, slotNum);
			doNext(pickItemToPlaceInArmorRack);
		}

		private function placeInWeaponRack(slotNum:int):void {
			placeIn(gearStorage, 0, 9, slotNum);
			doNext(pickItemToPlaceInWeaponRack);
		}

		private function placeInShieldRack(slotNum:int):void {
			placeIn(gearStorage, 36, 45, slotNum);
			doNext(pickItemToPlaceInShieldRack);
		}

		private function placeInJewelryBox(slotNum:int):void {
			placeIn(gearStorage, 18, 27, slotNum);
			doNext(pickItemToPlaceInJewelryBox);
		}

		private function placeInDresser(slotNum:int):void {
			placeIn(gearStorage, 27, 36, slotNum);
			doNext(pickItemToPlaceInDresser);
		}

		private function placeIn(storage:Array, startSlot:int, endSlot:int, slotNum:int):void {
			clearOutput();
			var x:int;
			var temp:int;
			var itype:ItemType = player.itemSlots[slotNum].itype;
			var qty:int = player.itemSlots[slotNum].quantity;
			var orig:int = qty;
			player.itemSlots[slotNum].emptySlot();
			for (x = startSlot; x < endSlot && qty > 0; x++) { //Find any slots which already hold the item that is being stored
				if (storage[x].itype == itype && storage[x].quantity < 5) {
					temp = 5 - storage[x].quantity;
					if (qty < temp) temp = qty;
					outputText("You add " + temp + "x " + itype.shortName + " into storage slot " + num2Text(x + 1 - startSlot) + ".\n");
					storage[x].quantity += temp;
					qty -= temp;
					if (qty == 0) return;
				}
			}
			for (x = startSlot; x < endSlot && qty > 0; x++) { //Find any empty slots and put the item(s) there
				if (storage[x].quantity == 0) {
					storage[x].setItemAndQty(itype, qty);
					outputText("You place " + qty + "x " + itype.shortName + " into storage slot " + num2Text(x + 1 - startSlot) + ".\n");
					qty = 0;
					return;
				}
			}
			outputText("There is no room for " + (orig == qty ? "" : "the remaining ") + qty + "x " + itype.shortName + ".  You leave " + (qty > 1 ? "them" : "it") + " in your inventory.\n");
			player.itemSlots[slotNum].setItemAndQty(itype, qty);
		}
	}
}


code:
/**
 * Created by aimozg on 18.01.14.
 */
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.Items.*

	public class AbstractSuccubus extends Monster
	{
		protected function whipAttack():void
		{
			if (findStatusEffect(StatusEffects.WhipReady) >= 0) {
				//Blind dodge change
				if (findStatusEffect(StatusEffects.Blind) >= 0) {
					outputText(capitalA + short + " swings her whip at you wildly, totally missing due to her blindness!!", false);
					combatRoundOver();
					return;
				}
				outputText("Grinning deviously, the succubus cracks her whip with expert skill, landing a painful blow on your ", false);
				var temp:int = rand(6);
				var damage:int;
				//Whip yo ass!
				if (temp == 0) {
					outputText("ass", false);
					damage = 4;
					game.dynStats("lus", 6 + int(player.sens / 20));
				}
				//Whip yo tits!
				if (temp == 1) {
					if (player.breastRows.length > 0 && player.biggestTitSize() > 0) outputText(player.allBreastsDescript() + "", false);
					else outputText("chest", false);
					damage = 9 - player.armor.def;
					if (damage <= 0) {
						outputText(" but you feel no pain thanks to your protection");
						damage = 0;
					}
					game.dynStats("lus", 4 + int(player.sens / 15));
				}
				//Whip yo groin
				if (temp == 2) {
					var groinProtection:int = 0;
					//Take armor in account.
					if (player.armor != ArmorLib.NOTHING) {
						if (player.armor.perk == "Light") groinProtection = 1;
						else if (player.armor.perk == "Medium") groinProtection = 2;
						else groinProtection = 3;
						//Certain armor affects protection.
						if (player.armor == armors.BEEARMR || player.armor == armors.SSARMOR || player.armor == armors.DBARMOR || player.armor == armors.TBARMOR) groinProtection = 2; //The only thing protecting your groin is a loincloth.
						if (player.armor == armors.GOOARMR) groinProtection = 2; //Goo armor is soft and gooey so not complete protection.
						if (player.armor == armors.LTHCARM) groinProtection = 0; //Lethicite armor exposes your groin.
					}
					//Wearing armored undergarments? BONUS POINTS!
					if (player.lowerGarment != UndergarmentLib.NOTHING) {
						if (player.lowerGarment == undergarments.SS_LOIN || player.lowerGarment == undergarments.SSPANTY) groinProtection += 1;
						else if (player.lowerGarment == undergarments.DS_LOIN || player.lowerGarment == undergarments.DSTHONG) groinProtection += 2;
					}
					//Apply damage
					if (groinProtection >= 3) {
						outputText("groin but luckily you're wearing groin protection");
						damage = 0;
					}
					else {
						if (player.gender == 0) {
							outputText("groin", false);
							damage = 5;
							damage = int(damage / (groinProtection + 1));
						}
						if (player.gender == 1) {
							outputText("groin, dealing painful damage to your " + player.multiCockDescriptLight() + ", doubling you over in agony", false);
							damage = int((player.maxHP()) / 4);
							if (groinProtection > 0) {
								outputText("! Of course, it would have been worse if you didn't wear groin protection");
								damage = int(damage / (groinProtection + 1));
							}
							damage = player.reduceDamage(damage);
							if (damage < 20) damage = 10;
							game.dynStats("lus", -15);
						}
						if (player.gender == 2) {
							outputText("groin, making your " + player.vaginaDescript(0) + " sting with pain", false);
							damage = 10;
							game.dynStats("lus", -8);
						}
						if (player.gender == 3) {
							outputText("groin, dealing painful damage to your " + player.multiCockDescriptLight() + " and " + player.vaginaDescript(0) + ", doubling you over in agony", false);
							damage = int((player.maxHP()) / 3)
							if (groinProtection > 0) {
								outputText("! Of course, it would have been worse if you didn't wear groin protection");
								damage = int(damage / (groinProtection + 1));
							}
							damage = player.reduceDamage(damage);
							if (damage < 30) damage = 30;
							game.dynStats("lus", -20);
						}
					}
				}
				//Whip yo legs
				if (temp == 3) {
					outputText("legs", false);
					damage = 7;
				}
				//Whip yo arms
				if (temp == 4) {
					outputText("arms", false);
					damage = 8;
				}
				//Whip yo neck
				if (temp == 5) {
					outputText("neck (24)", false);
					damage = 24;
				}
				outputText("! ", false);
				player.takeDamage(damage, true);
			}
			else {
				outputText("The succubus flicks her wrist, allowing a whip-like cord to slither out from the palm of her clawed hand.  She cracks the whip experimentally, cackling with glee.", false);
				createStatusEffect(StatusEffects.WhipReady, 0, 0, 0, 0);
				str += 20;
				this.weaponName = "whip";
				this.weaponVerb = "brutal whip-crack";
			}
			combatRoundOver();
		}

		public function AbstractSuccubus()
		{
		}

		protected function kissAttack():void
		{
			//[Kiss of Death Text]
			outputText("The succubus dances forwards, cocking her elbow back for a vicious strike.", false);
			//avoid!
			if (player.spe > spe && rand(4) == 0 || (player.findPerk(PerkLib.Evade) >= 0 && rand(4) == 0) || (player.findPerk(PerkLib.Misdirection) >= 0 && rand(4) == 0 && player.armorName == "red, high-society bodysuit")) {
				outputText("  You start to sidestep and realize it's a feint.   Ducking low, you slide under her real attack... a kiss?!  ", false);
				if (player.lust >= 70) outputText("  Maybe you shouldn't have bothered to move, it might have been fun.", false);
			}
			//get hit
			else {
				outputText("  You start to dodge to the side, but she shifts direction expertly and plants a wet kiss on your lips.  She spins and dodges away with a ballet dancer's grace, leaving you to wonder what just happened.  ", false);
				if (player.findStatusEffect(StatusEffects.KissOfDeath) < 0) player.createStatusEffect(StatusEffects.KissOfDeath, 0, 0, 0, 0);
			}
			combatRoundOver();
		}

		protected function seduceAttack():void
		{
			var temp:int;
			//determine which method of teasing you use
			temp = rand(3);
			//Butt slap!
			if (temp == 0) {
				outputText(capitalA + short + " slaps her " + Appearance.buttDescriptionShort(this), false);
				if (buttRating >= 10) {
					outputText(", making it jiggle delightfully.", false);
					//85% success rate for the jiggly girls
					if (rand(100) <= 95) {
						game.dynStats("lus", rand(buttRating) + 10);
						outputText("\nThe display is quite arousing.", false);
					}
					else outputText("\nYou're unimpressed.\n\n", false);
				}
				else {
					outputText(".", false);
					//50%ish chance of success for the tight butted.
					if (rand(100) <= (70 + buttRating * 2)) {
						game.dynStats("lus", rand(buttRating) + 9);
						outputText("\nThe display is quite arousing.", false);
					}
					else outputText("\nYou're unimpressed.\n\n", false);
				}
			}
			//Jiggly-tits
			if (temp == 1 && breastRows[0].breastRating >= 2) {
				//rand(breastRating) + breastRows*BreastperRow
				//Single breast row
				if (breastRows.length == 1) {
					//50+ breastsize% success rate
					outputText(capitalA + short + " caresses some of her ample chest-flesh before shaking it from side to side enticingly.", false);
					if (lust >= 50) outputText("  " + pronoun2 + " hard nipples seem to demand your attention.", false);
					if (rand(100) <= (65 + biggestTitSize())) {
						game.dynStats("lus", rand(breastRows[0].breastRating) + breastRows.length + 10);
						outputText("\nThe display is quite arousing.", false);
					}
					else outputText("\nYou're unimpressed.\n\n", false);
				}
				if (breastRows.length > 1) {
					//50 + 10% per breastRow + breastSize%
					outputText(capitalA + short + " caresses " + pronoun2 + " some of her rows of ample chest-flesh before shaking it all from side to side enticingly.", false);
					if (lust >= 50) outputText(", your " + player.nippleDescript(0) + "s painfully visible.", false);
					else outputText(".", false);
					if (rand(100) <= (54 + (breastRows.length - 1) * 15 + breastRows[0].breastRating)) {
						game.dynStats("lus", rand(breastRows[0].breastRating) + breastRows.length * breastRows[0].breasts + 5);
						outputText("\nThe display is quite arousing.", false);
					}
					else outputText("\nYou're unimpressed.\n\n", false);
				}
			}
			//Genetals flash!
			if (temp == 2) {
				outputText(capitalA + short + " reaches down and strokes her moist lips.  She sighs and licks her fingers clean, giving you a smoldering gaze.", false);
				//Success = 50% + 10% times each cock/vagina
				//rand(vaginas*2 + cocks*2) + wetness and/or length/6
				if (rand(101) <= (65 + vaginas.length * 10 + cocks.length * 10)) {
					game.dynStats("lus", rand(vaginas.length * 2 + cocks.length * 2) + 13);
					outputText("\nThe display is quite arousing.", false);
				}
				else outputText("\nYou're unimpressed.\n\n", false);
			}
			combatRoundOver();
		}
	}
}

license: unknown


code:
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.internals.*;
	import classes.GlobalFlags.*;

	public class Goblin extends Monster
	{
		protected function goblinDrugAttack():void {
			var temp2:Number = rand(2);
			var multiplier:Number = 1; //Higher tier goblins have powerful potions.
			if (short == "goblin assassin") multiplier += 0.2;
			if (short == "goblin shaman") multiplier += 0.4;
			if (short == "goblin warrior") multiplier += 0.5;
			if (short == "goblin elder") multiplier += 1;
			multiplier += player.newGamePlusMod() * 0.5;
			if (short == "Tamani") temp2 = rand(5);
			if (short == "Tamani's daughters") temp2 = rand(5);
			var color:String = "";
			if (temp2 == 0) color = "red";
			if (temp2 == 1) color = "green";
			if (temp2 == 2) color = "blue";
			if (temp2 == 3) color = "white";
			if (temp2 == 4) color = "black";
			//Throw offensive potions at the player
			if (color != "blue") {
				if (short == "Tamani's daughters") outputText("Tamani uncorks a glass bottle full of " + color + " fluid and swings her arm, flinging a wave of fluid at you.", false);
				else outputText(capitalA + short + " uncorks a glass bottle full of " + color + " fluid and swings her arm, flinging a wave of fluid at you.", false);
			}
			//Drink blue pots
			else {
				if (short == "Tamani's daughters") {
					outputText("Tamani pulls out a blue vial and uncaps it, then douses the mob with the contents.", false);
					if (HPRatio() < 1) {
						outputText("  Though less effective than ingesting it, the potion looks to have helped the goblins recover from their wounds!\n", false);
						addHP(80 * multiplier);
					}
					else outputText("  There doesn't seem to be any effect.\n", false);
					outputText("\n", false);
				}
				else {
					outputText(capitalA + short + " pulls out a blue vial and uncaps it, swiftly downing its contents.", false);
					if (HPRatio() < 1) {
						outputText("  She looks to have recovered from some of her wounds!\n", false);
						addHP((eMaxHP() / 4) * multiplier);
						if (short == "Tamani") addHP((eMaxHP() / 4) * multiplier);
					}
					else outputText("  There doesn't seem to be any effect.\n", false);
					combatRoundOver();
				}
				return;
			}
			//Dodge chance!
			if ((player.findPerk(PerkLib.Evade) >= 0 && rand(10) <= 3) || (rand(100) < player.spe/5)) {
				outputText("\nYou narrowly avoid the gush of alchemic fluids!\n", false);
			}
			else {
				//Get hit!
				if (color == "red") {
					//Temporary heat
					outputText("\nThe red fluids hit you and instantly soak into your skin, disappearing.  Your skin flushes and you feel warm.  Oh no...\n", false);
					if (player.findStatusEffect(StatusEffects.TemporaryHeat) < 0) player.createStatusEffect(StatusEffects.TemporaryHeat, 0, multiplier, 0, 0);
				}
				else if (color == "green") {
					//Green poison
					outputText("\nThe greenish fluids splash over you, making you feel slimy and gross.  Nausea plagues you immediately - you have been poisoned!\n", false);
					if (player.findStatusEffect(StatusEffects.Poison) < 0) player.createStatusEffect(StatusEffects.Poison, 0, multiplier, 0, 0);
				}
				else if (color == "white") {
					//sticky flee prevention
					outputText("\nYou try to avoid it, but it splatters the ground around you with very sticky white fluid, making it difficult to run.  You'll have a hard time escaping now!\n", false);
					if (player.findStatusEffect(StatusEffects.NoFlee) < 0) player.createStatusEffect(StatusEffects.NoFlee, 0, 0, 0, 0);
				}
				else if (color == "black") {
					//Increase fatigue
					outputText("\nThe black fluid splashes all over you and wicks into your skin near-instantly.  It makes you feel tired and drowsy.\n", false);
					player.changeFatigue(10 + rand(25) * multiplier);
				}
			}
			if (!plural) combatRoundOver();
			else outputText("\n", false);
		}
		protected function goblinTeaseAttack():void {
			var det:Number = rand(3);
			if (short == "goblin" || short == "goblin assassin") {
				if (det == 0) outputText(capitalA + short + " runs her hands along her leather-clad body and blows you a kiss. \"Why not walk on the wild side?\" she asks.", false);
				if (det == 1) outputText(capitalA + short + " grabs her heel and lifts it to her head in an amazing display of flexibility.  She caresses her snatch and gives you a come hither look.", false);
				if (det == 2) outputText(capitalA + short + " bends over, putting on a show and jiggling her heart-shaped ass at you.  She looks over her shoulder and sucks on her finger, batting her eyelashes.", false);
			}
			else if (short == "goblin warrior") {
				if (det == 0) outputText(capitalA + short + " runs her hands along her metal-clad body and blows you a kiss. \"Why not walk on the wild side?\" she asks.", false);
				if (det == 1) outputText(capitalA + short + " grabs her heel and lifts it to her head in an amazing display of flexibility despite the armor she's wearing.  She caresses her snatch and gives you a come hither look.", false);
				if (det == 2) outputText(capitalA + short + " bends over, putting on a show and jiggling her heart-shaped ass at you.  She looks over her shoulder and sucks on her finger, batting her eyelashes.", false);
			}
			else if (short == "goblin shaman") {
				if (det == 0) outputText(capitalA + short + " runs her hands along her leather-clad body and blows you a kiss. \"Why not walk on the wild side?\" she asks.", false);
				if (det == 1) outputText(capitalA + short + " grabs her heel and lifts it to her head in an amazing display of flexibility.  She lifts her loincloth and caresses her snatch and gives you a come hither look.", false);
				if (det == 2) outputText(capitalA + short + " bends over, putting on a show and jiggling her heart-shaped ass at you.  She looks over her shoulder and sucks on her finger, batting her eyelashes.", false);
			}
			else if (short == "goblin elder") {
				if (det == 0) outputText(capitalA + short + " runs her hands along her bone-clad body and blows you a kiss. \"Why not walk on the wild side?\" she asks.", false);
				if (det == 1) outputText(capitalA + short + " grabs her heel and lifts it to her head in an amazing display of flexibility.  She lifts her loincloth and caresses her snatch and gives you a come hither look.", false);
				if (det == 2) outputText(capitalA + short + " bends over, putting on a show and jiggling her heart-shaped ass at you.  She looks over her shoulder and sucks on her finger, batting her eyelashes.", false);
			}
			var lustDmg:int = rand(player.lib / 10) + 8;
			if (short == "goblin assassin") lustDmg *= 1.4;
			if (short == "goblin warrior") lustDmg *= 1.6;
			if (short == "goblin shaman") lustDmg *= 1.6;
			if (short == "goblin elder") lustDmg *= 2;
			game.dynStats("lus", lustDmg);
			outputText("  The display distracts you long enough to prevent you from taking advantage of her awkward pose, leaving you more than a little flushed.\n\n", false);
			combatRoundOver();
		}

		override public function defeated(hpVictory:Boolean):void
		{
			game.goblinScene.gobboRapeIntro();
		}

		override public function won(hpVictory:Boolean, pcCameWorms:Boolean):void
		{
			if (player.gender == 0 || flags[kFLAGS.SFW_MODE] > 0) {
				outputText("You collapse in front of the goblin, too wounded to fight.  She giggles and takes out a tube of lipstick smearing it whorishly on your face.  You pass into unconsciousness immediately.  It must have been drugged.", false);
				game.combat.cleanupAfterCombat();
			} else if (pcCameWorms) {
				outputText("\n\nThe goblin's eyes go wide and she turns to leave, no longer interested in you.", false);
				player.orgasm();
				doNext(game.combat.cleanupAfterCombat);
			} else {
				game.goblinScene.goblinRapesPlayer();
			}
		}

		public function Goblin(noInit:Boolean=false)
		{
			if (noInit) return;
			this.a = "the ";
			this.short = "goblin";
			this.imageName = "goblin";
			this.long = "The goblin before you is a typical example of her species, with dark green skin, pointed ears, and purple hair that would look more at home on a punk-rocker.  She's only about three feet tall, but makes up for it with her curvy body, sporting hips and breasts that would entice any of the men in your village were she full-size.  There isn't a single scrap of clothing on her, just lewd leather straps and a few clinking pouches.  She does sport quite a lot of piercings – the most noticeable being large studs hanging from her purple nipples.  Her eyes are fiery red, and practically glow with lust.  This one isn't going to be satisfied until she has her way with you.  It shouldn't be too hard to subdue such a little creature, right?";
			this.createVagina(false, VAGINA_WETNESS_DROOLING, VAGINA_LOOSENESS_NORMAL);
			this.createStatusEffect(StatusEffects.BonusVCapacity, 40, 0, 0, 0);
			createBreastRow(Appearance.breastCupInverse("E"));
			this.ass.analLooseness = ANAL_LOOSENESS_TIGHT;
			this.ass.analWetness = ANAL_WETNESS_DRY;
			this.createStatusEffect(StatusEffects.BonusACapacity,30,0,0,0);
			this.tallness = 35 + rand(4);
			this.hipRating = HIP_RATING_AMPLE+2;
			this.buttRating = BUTT_RATING_LARGE;
			this.skinTone = "dark green";
			this.hairColor = "purple";
			this.hairLength = 4;
			initStrTouSpeInte(12, 13, 35, 42);
			initLibSensCor(45, 45, 60);
			this.weaponName = "fists";
			this.weaponVerb="tiny punch";
			this.armorName = "leather straps";
			this.lust = 50;
			this.temperment = TEMPERMENT_RANDOM_GRAPPLES;
			this.level = 1;
			this.gems = rand(5) + 5;
			this.drop = new WeightedDrop().
					add(consumables.GOB_ALE,5).
					addMany(1,consumables.L_DRAFT,
							consumables.PINKDYE,
							consumables.BLUEDYE,
							consumables.ORANGDY,
							consumables.PURPDYE);
			this.special1 = goblinDrugAttack;
			this.special2 = goblinTeaseAttack;
			checkMonster();
		}

	}

}


code:
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.internals.*;
	import classes.GlobalFlags.*;

	public class GoblinAssassin extends Monster
	{
		protected function goblinDrugAttack():void {
			var temp2:Number = rand(5);
			var color:String = "";
			if (temp2 == 0) color = "red";
			if (temp2 == 1) color = "green";
			if (temp2 == 2) color = "blue";
			if (temp2 == 3) color = "white";
			if (temp2 == 4) color = "black";
			//Throw offensive potions at the player
			if (color != "blue") {
				outputText(capitalA + short + " uncorks a glass bottle full of " + color + " fluid and swings her arm, flinging a wave of fluid at you.", false);
			}
			//Drink blue pots
			else {
				outputText(capitalA + short + " pulls out a blue vial and uncaps it, swiftly downing its contents.", false);
				if (HPRatio() < 1) {
					outputText("  She looks to have recovered from some of her wounds!\n", false);
					addHP(eMaxHP() /4);
				}
				else outputText("  There doesn't seem to be any effect.\n", false);
			}
			//Dodge chance!
			if ((player.findPerk(PerkLib.Evade) >= 0 && rand(10) <= 3) || (rand(100) < player.spe/5)) {
				outputText("\nYou narrowly avoid the gush of alchemic fluids!\n", false);
			}
			//Get hit!
			//Temporary heat
			if (color == "red") {
				outputText("\nThe red fluids hit you and instantly soak into your skin, disappearing.  Your skin flushes and you feel warm.  Oh no...\n", false);
				if (player.findStatusEffect(StatusEffects.TemporaryHeat) < 0) player.createStatusEffect(StatusEffects.TemporaryHeat,0,0,0,0);
			}
			//Green poison
			if (color == "green") {
				outputText("\nThe greenish fluids splash over you, making you feel slimy and gross.  Nausea plagues you immediately - you have been poisoned!\n", false);
				if (player.findStatusEffect(StatusEffects.Poison) < 0) player.createStatusEffect(StatusEffects.Poison,0,0,0,0);
			}
			//sticky flee prevention
			if (color == "white") {
				outputText("\nYou try to avoid it, but it splatters the ground around you with very sticky white fluid, making it difficult to run.  You'll have a hard time escaping now!\n", false);
				if (player.findStatusEffect(StatusEffects.NoFlee) < 0) player.createStatusEffect(StatusEffects.NoFlee,0,0,0,0);
			}
			//Increase fatigue
			if (color == "black") {
				outputText("\nThe black fluid splashes all over you and wicks into your skin near-instantly.  It makes you feel tired and drowsy.\n", false);
				player.changeFatigue(10 + rand(25));
			}
			combatRoundOver();
			return;
		}
		//Lust Needle
		protected function lustNeedle():void {
			outputText("With a swift step, the assassin vanishes, her movements too quick for you to follow. You take a sharp breath as you feel her ample thighs clench your head in between them, her slick cunt in full view as you take in her scent.");
			//Miss
			if (player.getEvasionRoll())
			{
				//Miss:
				outputText("\nYou’ve already prepared, however, as you hold your breath and grab the goblin by her sides. Unhindered by her advance, you take the opportunity to move backwards, throwing the goblin off balance and leaving you only faintly smelling of her pussy.");
				game.dynStats("lus", rand(player.lib/10) +4);
			}
			//Hit:
			else
			{
				outputText("\nYou’re far too distracted to notice the needle injected into the back of your neck, but by the time she flips back into her original position you already feel the contents of the syringe beginning to take effect.");
				game.dynStats("lus", rand(player.lib/4) +20);
			}
			combatRoundOver();
		}
		//Dual Shot
		protected function dualShot():void {
			outputText("The assassin throws a syringe onto the ground, shattering it and allowing the dissipating smoke from its contents to distract you long enough for her to slip underneath you. With a quick flick of her wrists two needles are placed into her hands, though you’ve already caught wind of her movements.");
			//Miss:
			if (player.getEvasionRoll())
			{
				outputText("\nYou jump backwards, far enough to avoid her quick thrust upwards as she attempts to lick the area in which your crotch once stood. Realising her situation, she quickly removes herself from the ground and faces you, more determined than before.");
			}
			//Hit:
			else {
				outputText("\nBefore you can do anything to stop her, she lifts her head and takes a swift lick of your crotch, taking a small moan from you and giving her enough time to stab into the back of your knees. She rolls out of the way just as you pluck the two needles out and throw them back to the ground. They didn’t seem to have anything in them, but the pain is enough to make you stagger. ");
				//(Medium HP loss, small lust gain)
				var damage:int = int((str + weaponAttack + 40) - rand(player.tou) - player.armorDef);
				damage = player.takeDamage(damage, true);
			}
			combatRoundOver();
		}
		//Explosion
		protected function goblinExplosion():void {
			outputText("Without a second thought, the assassin pulls a thin needle from the belt wrapped around her chest and strikes it against the ground, causing a flame to erupt on the tip. She twirls forward, launching the needle in your direction which subsequently bursts apart and showers you with heat.");
			outputText("\nYou shield yourself from the explosion, though the goblin has already lit a second needle which she throws behind you, launching your body forwards as it explodes behind your back. ");
			//(High HP loss, no lust gain)
			var damage:int = 25 + rand(75);
			damage = player.takeDamage(damage, true);
			combatRoundOver();
		}
		override public function defeated(hpVictory:Boolean):void
		{
			game.goblinAssassinScene.gobboAssassinRapeIntro();

		}
		override public function won(hpVictory:Boolean, pcCameWorms:Boolean):void
		{
			if (player.gender == 0 || flags[kFLAGS.SFW_MODE] > 0) {
				outputText("You collapse in front of the goblin, too wounded to fight.  She growls and kicks you in the head, making your vision swim. As your sight fades, you hear her murmur, \"<i>Fucking dicks can't even bother to grow a dick or cunt.</i>\"", false);
				game.combat.cleanupAfterCombat();
			}
			else {
				game.goblinAssassinScene.gobboAssassinBeatYaUp();
			}
		}
		public function GoblinAssassin(noInit:Boolean=false)
		{
			if (noInit) return;
			this.a = "the ";
			this.short = "goblin assassin";
			this.imageName = "goblinassassin";
			this.long = "Her appearance is that of a regular goblin, curvy and pale green, perhaps slightly taller than the norm. Her wavy, untamed hair is a deep shade of blue, covering her pierced ears and reaching just above her shoulders. Her soft curves are accentuated by her choice of wear, a single belt lined with assorted needles strapped across her full chest and a pair of fishnet stockings reaching up to her thick thighs. She bounces on the spot, preparing to dodge anything you might have in store, though your eyes seem to wander towards her bare slit and jiggling ass. Despite her obvious knowledge in combat, she’s a goblin all the same – a hard cock can go a long way.";
			// this.plural = false;
			this.createVagina(false, VAGINA_WETNESS_DROOLING, VAGINA_LOOSENESS_NORMAL);
			this.createStatusEffect(StatusEffects.BonusVCapacity, 90, 0, 0, 0);
			createBreastRow(Appearance.breastCupInverse("E"));
			this.ass.analLooseness = ANAL_LOOSENESS_NORMAL;
			this.ass.analWetness = ANAL_WETNESS_DRY;
			this.createStatusEffect(StatusEffects.BonusACapacity,50,0,0,0);
			this.tallness = 35 + rand(4);
			this.hipRating = HIP_RATING_AMPLE+2;
			this.buttRating = BUTT_RATING_LARGE;
			this.skinTone = "dark green";
			this.hairColor = "blue";
			this.hairLength = 7;
			initStrTouSpeInte(45, 55, 110, 95);
			initLibSensCor(65, 35, 60);
			this.weaponName = "needles";
			this.weaponVerb="stabbing needles";
			this.armorName = "leather straps";
			this.bonusHP = 70;
			this.lust = 50;
			this.temperment = TEMPERMENT_RANDOM_GRAPPLES;
			this.level = 10;
			this.gems = rand(50) + 25;
			this.drop = new WeightedDrop().
					add(consumables.GOB_ALE, 5).
					addMany(1, consumables.L_DRAFT,
							consumables.PINKDYE,
							consumables.BLUEDYE,
							consumables.ORANGDY,
							consumables.PURPDYE);// TODO this is a copy of goblin drop. consider replacement with higher-lever stuff
			checkMonster();
		}

		override protected function performCombatAction():void
		{
			var actions:Array = [eAttack,goblinDrugAttack,lustNeedle,dualShot,goblinExplosion];
			actions[rand(actions.length)]();
		}
	}
}


code:
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.internals.*;
	import classes.GlobalFlags.*;

	public class GoblinQueen extends Goblin
	{

		public function GoblinQueen()
		{
			this.a = "the ";
			this.short = "goblin queen";
			this.imageName = "goblinqueen";
			this.long = "The goblin before you stands nearly four feet tall. Her ears appear to be pierced more times than the amount of piercings a typical goblin has. Her hair is dark green and her skin color is a vibrant yellow, a sheer rarity. She’s unlike most of the goblins you’ve seen. She’s wielding a staff in her right hand. In addition to the straps covering her body, she’s wearing a necklace seemingly carved with what looks like shark teeth. She's wielding a glowing sword in her right hand and a shield in her left hand. ";
			this.createVagina(false, VAGINA_WETNESS_DROOLING, VAGINA_LOOSENESS_NORMAL);
			this.createStatusEffect(StatusEffects.BonusVCapacity, 40, 0, 0, 0);
			createBreastRow(Appearance.breastCupInverse("FF"));
			this.ass.analLooseness = ANAL_LOOSENESS_TIGHT;
			this.ass.analWetness = ANAL_WETNESS_DRY;
			this.createStatusEffect(StatusEffects.BonusACapacity,30,0,0,0);
			this.tallness = 47;
			this.hipRating = HIP_RATING_AMPLE+2;
			this.buttRating = BUTT_RATING_LARGE;
			this.skinTone = "dark green";
			this.hairColor = "dark green";
			this.hairLength = 4;
			initStrTouSpeInte(85, 65, 70, 100);
			initLibSensCor(55, 35, 65);
			this.weaponName = "sword";
			this.weaponVerb = "slash";
			this.weaponAttack = 14;
			this.armorName = "fur loincloth";
			this.armorDef = 6;
			this.fatigue = 0;
			this.bonusHP = 275;
			this.lust = 35;
			this.lustVuln = 0.4;
			this.temperment = TEMPERMENT_RANDOM_GRAPPLES;
			this.level = 14;
			this.gems = rand(15) + 15;
			this.drop = new WeightedDrop().
					add(consumables.GOB_ALE,5).
					add(weapons.W_STAFF,1).
					add(armors.FURLOIN,1).
					add(jewelries.MYSTRNG,1).
					addMany(1,consumables.L_DRAFT,
							consumables.PINKDYE,
							consumables.BLUEDYE,
							consumables.ORANGDY,
							consumables.GREEN_D,
							consumables.PURPDYE);
			this.special1 = goblinDrugAttack;
			this.special2 = goblinTeaseAttack;
			this.special3 = castSpell;
			checkMonster();
		}

	}

}


code:
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.internals.*;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.GlobalFlags.kFLAGS;

	public class GoblinShaman extends Goblin
	{
		public var spellCostCharge:int = 6;
		public var spellCostBlind:int = 8;
		public var spellCostWhitefire:int = 12;
		public var spellCostArouse:int = 6;
		public var spellCostHeal:int = 8;
		public var spellCostMight:int = 10;

		public function castSpell():void {
			var spellChooser:int = rand(6);
			//Makes sure to not stack spell effects.
			if (lust < 50) spellChooser = rand(3);
			if (lust > 75) spellChooser = rand(3) + 3;
			if (spellChooser == 0 && findStatusEffect(StatusEffects.ChargeWeapon) >= 0) {
				spellChooser = rand(5) + 1;
			}
			if (spellChooser == 4 && HPRatio() >= 0.7) {
				spellChooser++;
			}
			if (spellChooser == 5 && findStatusEffect(StatusEffects.Might) >= 0) {
				spellChooser = rand(5);
				if (spellChooser == 0 && findStatusEffect(StatusEffects.ChargeWeapon) >= 0) spellChooser++;
			}
			//Spell time!
			//Charge Weapon
			if (spellChooser == 0 && fatigue <= (100 - spellCostCharge)) {
				outputText("The goblin utters word of power, summoning an electrical charge around her staff. It looks like she'll deal more physical damage now!");
				createStatusEffect(StatusEffects.ChargeWeapon, 25 * spellMultiplier(), 0, 0, 0);
				this.weaponAttack += 25 * spellMultiplier();
				fatigue += spellCostCharge;
			}
			//Blind
			else if (spellChooser == 1 && fatigue <= (100 - spellCostBlind)) {
				outputText("The goblin glares at you and points at you! A bright flash erupts before you!  ");
				if (rand(player.inte / 5) <= 4) {
					outputText("You are blinded!");
					player.createStatusEffect(StatusEffects.Blind, 1 + rand(3), 0, 0, 0);
				}
				else {
					outputText("You manage to blink in the nick of time!");
				}
				fatigue += spellCostBlind;
			}
			//Whitefire
			else if (spellChooser == 2 && fatigue <= (100 - spellCostWhitefire)) {
				outputText("The goblin narrows her eyes and focuses her mind with deadly intent. She snaps her fingers and you are enveloped in a flash of white flames!  ");
				var damage:int = inte + rand(50) * spellMultiplier();
				if (player.isGoo()) {
					damage *= 1.5;
					outputText("It's super effective! ");
				}
				if (flags[kFLAGS.GAME_DIFFICULTY] == 1) damage *= 1.15;
				else if (flags[kFLAGS.GAME_DIFFICULTY] == 2) damage *= 1.3;
				else if (flags[kFLAGS.GAME_DIFFICULTY] >= 3) damage *= 1.5;
				player.takeDamage(damage, true);
				fatigue += spellCostWhitefire;
			}
			//Arouse
			else if (spellChooser == 3 && fatigue <= (100 - spellCostArouse)) {
				outputText("She makes a series of arcane gestures, drawing on her lust to inflict it upon you! ");
				var lustDamage:int = (inte / 10) + (player.lib / 10) + rand(10) * spellMultiplier();
				lustDamage = lustDamage * (player.lustPercent() / 100);
				game.dynStats("lus", lustDamage, "resisted", false);
				outputText(" (" + (Math.round(lustDamage * 10) / 10) + ")");
				fatigue += spellCostArouse;
			}
			//Heal
			else if (spellChooser == 4 && fatigue <= (100 - spellCostHeal)) {
				outputText("She focuses on her body and her desire to end pain, trying to draw on her arousal without enhancing it.");
				var temp:int = int(10 + (inte/2) + rand(inte/3)) * spellMultiplier();
				outputText("She flushes with success as her wounds begin to knit! (+" + temp + ").", false);
				addHP(temp);
				fatigue += spellCostHeal;
			}
			//Might
			else if (spellChooser == 5 && fatigue <= (100 - spellCostMight)) {
				outputText("She flushes, drawing on her body's desires to empower her muscles and toughen her up.");
				outputText("The rush of success and power flows through her body.  She feels like she can do anything!", false);
				createStatusEffect(StatusEffects.Might, 20 * spellMultiplier(), 20 * spellMultiplier(), 0, 0);
				str += 20 * spellMultiplier();
				tou += 20 * spellMultiplier();
				fatigue += spellCostMight;
			}
			combatRoundOver();
		}

		private function spellMultiplier():Number {
			var mult:Number = 1;
			mult += player.newGamePlusMod() * 0.5;
			return mult;
		}

		override protected function performCombatAction():void {
			var choice:Number = rand(8);
			if (choice < 3) eAttack();
			else if (choice == 3) goblinDrugAttack();
			else if (choice == 4) goblinTeaseAttack();
			else castSpell();
		}

		override public function defeated(hpVictory:Boolean):void
		{
			game.goblinShamanScene.goblinShamanRapeIntro();
		}
		override public function won(hpVictory:Boolean, pcCameWorms:Boolean):void
		{
			if (player.gender == 0 || flags[kFLAGS.SFW_MODE] > 0) {
				outputText("You collapse in front of the goblin, too wounded to fight.  She growls and kicks you in the head, making your vision swim. As your sight fades, you hear her murmur, \"Fucking dicks can't even bother to grow a dick or cunt.\"", false);
				game.combat.cleanupAfterCombat();
			}
			else {
				game.goblinShamanScene.goblinShamanBeatYaUp();
			}
		}

		public function GoblinShaman()
		{
			this.a = "the ";
			this.short = "goblin shaman";
			this.imageName = "goblinshaman";
			this.long = "The goblin before you stands approximately three feet and a half. Her ears appear to be pierced more times than the amount of piercings a typical goblin has. Her hair is deep indigo. She’s unlike most of the goblins you’ve seen. She’s wielding a staff in her right hand. In addition to the straps covering her body, she’s wearing a necklace seemingly carved with what looks like shark teeth. She’s also wearing a tattered loincloth, unlike most goblins who would show off their pussies. From the looks of one end of her staff glowing, she’s clearly a shaman!";
			if (player.hasCock()) this.long += "  She's clearly intent on casting you into submission just so she can forcibly make you impregnate her.";
			this.createVagina(false, VAGINA_WETNESS_DROOLING, VAGINA_LOOSENESS_NORMAL);
			this.createStatusEffect(StatusEffects.BonusVCapacity, 40, 0, 0, 0);
			createBreastRow(Appearance.breastCupInverse("E"));
			this.ass.analLooseness = ANAL_LOOSENESS_TIGHT;
			this.ass.analWetness = ANAL_WETNESS_DRY;
			this.createStatusEffect(StatusEffects.BonusACapacity,30,0,0,0);
			this.tallness = 44 + rand(7);
			this.hipRating = HIP_RATING_AMPLE+2;
			this.buttRating = BUTT_RATING_LARGE;
			this.skinTone = "dark green";
			this.hairColor = "indigo";
			this.hairLength = 4;
			initStrTouSpeInte(75, 50, 70, 87);
			initLibSensCor(45, 45, 60);
			this.weaponName = "wizard staff";
			this.weaponVerb = "bludgeon";
			this.weaponAttack = 14;
			this.armorName = "fur loincloth";
			this.armorDef = 6;
			this.fatigue = 0;
			this.bonusHP = 275;
			this.lust = 35;
			this.lustVuln = 0.4;
			this.temperment = TEMPERMENT_RANDOM_GRAPPLES;
			this.level = 14;
			this.gems = rand(15) + 15;
			this.drop = new WeightedDrop().
					add(consumables.GOB_ALE,5).
					add(weapons.W_STAFF,1).
					add(undergarments.FURLOIN,1).
					add(jewelries.MYSTRNG, 1).
					add(jewelries.LIFERNG,1).
					addMany(1,consumables.L_DRAFT,
							consumables.PINKDYE,
							consumables.BLUEDYE,
							consumables.ORANGDY,
							consumables.GREEN_D,
							consumables.PURPDYE);
			this.special1 = goblinDrugAttack;
			this.special2 = goblinTeaseAttack;
			this.special3 = castSpell;
			checkMonster();
		}

	}

}


code:
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.internals.*;
	import classes.GlobalFlags.kGAMECLASS;
	import classes.GlobalFlags.kFLAGS;

	public class GoblinWarrior extends Goblin
	{
		public function slash():void {
			outputText("The goblin charges at you with her sword!  As soon as she approaches you, she swings her sword! ");
			if (player.getEvasionRoll()) {
				outputText("You avoid her slash!");
			}
			else {
				outputText("You fail to dodge and you get hit. ");
				//Get hit
				var damage:int = str + weaponAttack + rand(40);
				damage = player.reduceDamage(damage);
				player.takeDamage(damage, true);
			}
			combatRoundOver();
		}

		public function shieldBash():void {
			outputText("The goblin charges at you with her shield! ");
			if (player.getEvasionRoll()) {
				outputText("You avoid her shield bash!");
			}
			else {
				outputText("Her shield hits you! ");
				//Get hit
				if (rand(100) < 40 && player.findPerk(PerkLib.Resolute) < 0) {
					outputText("The impact from the shield has left you with a concussion. You are stunned. ");
					player.createStatusEffect(StatusEffects.Stunned, 1, 0, 0, 0);
				}
				var damage:int = str + rand(10);
				damage = player.reduceDamage(damage);
				player.takeDamage(damage, true);
			}
			combatRoundOver();
		}

		public function warriorSpecial():void {
			if (rand(2) == 0) slash();
			else shieldBash();
		}

		override public function defeated(hpVictory:Boolean):void
		{
			game.goblinWarriorScene.goblinWarriorRapeIntro();
		}
		override public function won(hpVictory:Boolean, pcCameWorms:Boolean):void
		{
			if (player.gender == 0 || flags[kFLAGS.SFW_MODE] > 0) {
				outputText("You collapse in front of the goblin, too wounded to fight.  She growls and kicks you in the head, making your vision swim. As your sight fades, you hear her murmur, \"Fucking dicks can't even bother to grow a dick or cunt.\"", false);
				game.combat.cleanupAfterCombat();
			}
			else {
				game.goblinWarriorScene.gobboWarriorBeatYaUp();
			}
		}

		public function GoblinWarrior()
		{
			this.a = "the ";
			this.short = "goblin warrior";
			this.imageName = "goblinwarrior";
			this.long = "The goblin before you is slightly taller than most of the goblins and her hair is a deep red hue. She has dark green skin and her ears are pierced in several spots. Unlike most goblins you've seen, this one is well armed. She's wearing a metal breastplate that covers her torso, offering her more defense. There are more straps covering her legs than a goblin typically has. She's wielding a shortsword in her right hand and a wooden shield in her left hand. Despite how well-armed she is, her nipples and cooter are exposed.";
			if (player.hasCock()) this.long += "  She's clearly intent on beating you up just so she can forcibly make you impregnate her.";
			this.createVagina(false, VAGINA_WETNESS_DROOLING, VAGINA_LOOSENESS_NORMAL);
			this.createStatusEffect(StatusEffects.BonusVCapacity, 40, 0, 0, 0);
			createBreastRow(Appearance.breastCupInverse("E"));
			this.ass.analLooseness = ANAL_LOOSENESS_TIGHT;
			this.ass.analWetness = ANAL_WETNESS_DRY;
			this.createStatusEffect(StatusEffects.BonusACapacity,30,0,0,0);
			this.tallness = 44 + rand(7);
			this.hipRating = HIP_RATING_AMPLE+2;
			this.buttRating = BUTT_RATING_LARGE;
			this.skinTone = "dark green";
			this.hairColor = "red";
			this.hairLength = 4;
			initStrTouSpeInte(75, 50, 70, 72);
			initLibSensCor(45, 45, 60);
			this.weaponName = "sword and shield";
			this.weaponVerb = "slash";
			this.weaponAttack = 14;
			this.armorName = "platemail";
			this.armorDef = 12;
			this.bonusHP = 400;
			this.lust = 50;
			this.lustVuln = 0.44;
			this.temperment = TEMPERMENT_RANDOM_GRAPPLES;
			this.level = 16;
			this.gems = rand(15) + 15;
			this.drop = new WeightedDrop().
					add(consumables.GOB_ALE,5).
					addMany(1,consumables.L_DRAFT,
							consumables.PINKDYE,
							consumables.BLUEDYE,
							consumables.ORANGDY,
							consumables.GREEN_D,
							consumables.PURPDYE);
			this.special1 = goblinDrugAttack;
			this.special2 = goblinTeaseAttack;
			this.special3 = warriorSpecial;
			checkMonster();
		}

	}

}


code:
package classes.Scenes.Monsters
{
	import classes.*;
	import classes.internals.*;
	import classes.GlobalFlags.kFLAGS;

	public class Imp extends Monster
	{
		override public function defeated(hpVictory:Boolean):void
		{
			game.flags[kFLAGS.DEMONS_DEFEATED]++;
			if (findStatusEffect(StatusEffects.KitsuneFight) >= 0) {
				game.forest.kitsuneScene.winKitsuneImpFight();
			} else {
				game.impScene.impVictory();
			}
		}

		override public function won(hpVictory:Boolean, pcCameWorms:Boolean):void
		{
			if (findStatusEffect(StatusEffects.KitsuneFight) >= 0) {
				game.forest.kitsuneScene.loseKitsuneImpFight();
			} else if (pcCameWorms) {
				outputText("\n\nThe imp grins at your already corrupted state...", false);
				player.lust = player.maxLust();
				doNext(game.impScene.impRapesYou);
			} else {
				game.impScene.impRapesYou();
			}
		}

		protected function lustMagicAttack():void {
			outputText("You see " + a + short + " make sudden arcane gestures at you!\n\n");
			game.dynStats("lus", player.lib / 10 + player.cor / 10 + 10);
			if (player.lust < 30) outputText("You feel strangely warm.  ");
			if (player.lust >= 30 && player.lust < 60) outputText("Blood rushes to your groin as a surge of arousal hits you, making your knees weak.  ");
			if (player.lust >= 60) outputText("Images of yourself fellating and fucking the imp assault your mind, unnaturally arousing you.  ");
			if (player.cocks.length > 0) {
				if (player.lust >= 60)
					outputText("You feel your " + player.multiCockDescriptLight() + " dribble pre-cum.");
				else if (player.lust >= 30 && player.cocks.length == 1)
					outputText("Your " + player.cockDescript(0) + " hardens, distracting you further.");
				else if (player.lust >= 30 && player.cocks.length > 1)
					outputText("Your " + player.multiCockDescriptLight() + " harden uncomfortably.");
				if (player.hasVagina()) outputText("  ");
			}
			if (player.lust >= 60 && player.hasVagina()) {
				switch (player.vaginas[0].vaginalWetness) {
					case VAGINA_WETNESS_NORMAL:
						outputText("Your " + player.allVaginaDescript() + " dampen" + (player.vaginas.length > 1 ? "" : "s") + " perceptibly.");
						break;
					case VAGINA_WETNESS_WET:
						outputText("Your crotch becomes sticky with girl-lust.");
						break;
					case VAGINA_WETNESS_SLICK:
						outputText("Your " + player.allVaginaDescript() + " become" + (player.vaginas.length > 1 ? "" : "s") + " sloppy and wet.");
						break;
					case VAGINA_WETNESS_DROOLING:
						outputText("Thick runners of girl-lube stream down the insides of your thighs.");
						break;
					case VAGINA_WETNESS_SLAVERING:
						outputText("Your " + player.allVaginaDescript() + " instantly soak" + (player.vaginas.length > 1 ? "" : "s") + " your groin.");
					default: //Dry vaginas are unaffected

				}
			}
			outputText("\n");
			if (player.lust >= player.maxLust())
				doNext(game.combat.endLustLoss);
			else doNext(game.playerMenu);
		}

		public function Imp(noInit:Boolean=false)
		{
			if (noInit) return;
			trace("Imp Constructor!");
			this.a = "the ";
			this.short = "imp";
			this.imageName = "imp";
			this.long = "An imp is short, only a few feet tall.  An unkempt mane of shaggy black hair hangs from his head, parted by two short curved horns.  His eyes are solid black, save for tiny red irises which glow with evil intent.  His skin is bright red, and unencumbered by clothing or armor, save for a small loincloth at his belt.  His feet are covered by tiny wooden sandals, and his hands tipped with sharp claws.  A pair of tiny but functional wings occasionally flap from his back.";
			// this.plural = false;
			this.createCock(rand(2) + 11, 2.5, CockTypesEnum.DEMON);
			this.balls = 2;
			this.ballSize = 1;
			createBreastRow(0);
			this.ass.analLooseness = ANAL_LOOSENESS_STRETCHED;
			this.ass.analWetness = ANAL_WETNESS_NORMAL;
			this.tallness = rand(24) + 25;
			this.hipRating = HIP_RATING_BOYISH;
			this.buttRating = BUTT_RATING_TIGHT;
			this.skinTone = "red";
			this.hairColor = "black";
			this.hairLength = 5;
			initStrTouSpeInte(20, 10, 25, 12);
			initLibSensCor(45, 45, 100);
			this.weaponName = "claws";
			this.weaponVerb="claw-slash";
			this.armorName = "leathery skin";
			this.lust = 40;
			this.temperment = TEMPERMENT_LUSTY_GRAPPLES;
			this.level = 1;
			this.gems = rand(5) + 5;
			this.drop = new WeightedDrop().
					add(consumables.SUCMILK,3).
					add(consumables.INCUBID,3).
					add(consumables.IMPFOOD,4);
			this.special1 = lustMagicAttack;
			this.wingType = WING_TYPE_IMP;
			checkMonster();
		}

	}

}


code:
package classes.Scenes.Monsters
{
	import classes.Monster;
	import classes.internals.WeightedDrop;
	import classes.CockTypesEnum;
	/**
	 * ...
	 * @author ...
	 */
	public class Mimic extends Monster
	{

		override public function won(hpVictory:Boolean, pcCameWorms:Boolean):void {
			game.mimicScene.mimicTentacle2();
		}

		override public function defeated(hpVictory:Boolean):void {
			game.mimicScene.killTheMimic();
		}

		private function mimicBite():void {
			outputText("The creature lashes out at you, attempting to bite you! ");
			if (player.getEvasionRoll()) {
				outputText("Thankfully you're quick enough to avoid its gaping maw!");
			}
			else {
				outputText("Ow! The mouth rends your arm and it hurts like hell! ");
				var damage:int = (10 + (str / 2) + rand(str / 3)) * (1 + (player.newGamePlusMod() * 0.3));
				damage = player.reduceDamage(damage);
				if (damage < 10) damage = 10;
				player.takeDamage(damage, true);
			}
			combatRoundOver();
		}

		public function Mimic(type:int)
		{
			this.a = "the ";
			this.short = "mimic";
			switch(type) {
				case 0:
					this.imageName = "mimic-stone";
					this.long = "This strange monster originally disguised as a huge block of grey stone covered in bizarre runes and symbols. Its surface appears to be grey and made of stone. There is a gaping maw with hundreds of teeth inside and a huge tongue lashing about.";
					break;
				case 1:
					this.imageName = "mimic-boob";
					this.long = "This strange monster originally disguised as a huge breast. Its surface appears to be pale, reminiscent of skin. There is a gaping maw where its nipple should be with hundreds of teeth inside and a tiny whippy tongue lashing about. Milky saliva seems to be leaking from its nightmarish mouth.";
					break;
				case 2:
					this.imageName = "mimic-cock";
					this.long = "This strange monster originally disguised as a huge penis. Its surface appears to be pale, reminiscent of skin. There is a gaping maw where its urethra should be with hundreds of teeth inside and a tiny whippy tongue lashing about. There are dozens of tentacles sprouting from its shaft.";
					break;
				case 3:
					this.imageName = "mimic-chest";
					this.long = "This strange monster originally disguised as a wooden chest. Its surface appears to be brown and made of wood. There is a gaping maw where the box and lid meet, with hundreds of teeth inside and a huge tongue lashing about.";
					break;
				default:
					this.imageName = "mimic";
			}
			if (type == 2)
				this.createCock(80, 16, CockTypesEnum.HUMAN);
			else
				this.initedGenitals = true;
			this.balls = 0;
			this.ballSize = 0;
			if (type == 1)
				createBreastRow(BREAST_CUP_JACQUES00);
			else
				createBreastRow(0);
			this.ass.analLooseness = ANAL_LOOSENESS_TIGHT;
			this.ass.analWetness = ANAL_WETNESS_DRY;
			this.tallness = rand(24) + 25;
			this.hipRating = HIP_RATING_BOYISH;
			this.buttRating = BUTT_RATING_TIGHT;
			if (type == 3)
				this.skinTone = "brown";
			if (type == 1 || type == 2)
				this.skinTone = "light";
			else
				this.skinTone = "gray";
			this.hairColor = "none";
			this.hairLength = 0;
			this.pronoun1 = "it";
			this.pronoun2 = "it";
			this.pronoun3 = "its";
			initStrTouSpeInte(30, 45, 15, 5);
			initLibSensCor(45, 45, 100);
			this.weaponName = "mouth";
			this.weaponVerb = "bite";
			this.weaponAttack = 20 + player.level;
			if (type == 3) {
				this.armorName = "wooden surface";
				this.armorDef = 10;
			}
			if (type == 2 || type == 1) {
				this.armorName = "flesh";
				this.armorDef = 0;
			}
			else {
				this.armorName = "stone surface";
				this.armorDef = 25;
			}
			this.lust = 10;
			this.lustVuln = 0;
			this.temperment = TEMPERMENT_LUSTY_GRAPPLES;
			this.level = 6;
			this.gems = rand(30) + 11;
			this.drop = new WeightedDrop().
					add(consumables.PPHILTR,4).
					add(consumables.NUMBOIL,4).
					add(consumables.HUMMUS_,3).
					add(consumables.INCUBID,1).
					add(consumables.SUCMILK,1).
					add(consumables.REDUCTO,1);
			this.special1 = mimicBite;
			checkMonster();
		}

	}

}