All pastes #47362 Raw Edit

Mine

public text v1 · immutable
#47362 ·published 2006-03-28 23:55 UTC
rendered paste body
Index: config/altsettings.properties
===================================================================
--- config/altsettings.properties	(revision 1682)
+++ config/altsettings.properties	(working copy)
@@ -23,9 +23,13 @@
 # - players get EXP/SP for crafting
 AltGameCreation = False
 
-# time multiplyer - bigger number = slower crafting, default was 15 now is 10 
-AltGameCreationSpeed = 10
+# time multiplier - bigger number ===> slower crafting but more XP/SP 
+AltGameCreationSpeed = 1
 
+# Additional XP/SP rate multiplier (for increased XP/SP)  default = 1
+AltGameCreationRateXp = 1
+AltGameCreationRateSp = 1
+
 # Alternative skill learn rules:
 # - all classes can learn all skills
 # - skills of another class costs x2 SP
Index: net/sf/l2j/Config.java
===================================================================
--- net/sf/l2j/Config.java	(revision 1682)
+++ net/sf/l2j/Config.java	(working copy)
@@ -80,15 +80,21 @@
 
     /** Character name template */
     public static String CNAME_TEMPLATE;
-
+ 
     /** Global chat state */
     public static String  DEFAULT_GLOBAL_CHAT;
     /** For test servers - evrybody has admin rights */
     public static boolean EVERYBODY_HAS_ADMIN_RIGHTS;
     /** Alternative game crafting */
     public static boolean ALT_GAME_CREATION;
-    /** Alternative game crafting speed mutiplyer - default 10,  bigger number -> slower */
-    public static int ALT_GAME_CREATION_SPEED;
+    /** Alternative game crafting speed mutiplier - default 0 (fastest but still not instant) */
+    public static double ALT_GAME_CREATION_SPEED;
+    /** Alternative game crafting XP rate multiplier - default 1*/
+    public static double ALT_GAME_CREATION_XP_RATE;
+    /** Alternative game crafting SP rate multiplier - default 1*/
+    public static double ALT_GAME_CREATION_SP_RATE;
+    
+    
     /** Alternative game skill learning */
     public static boolean ALT_GAME_SKILL_LEARN;
     /** Cancel ATTACK/cast by hit */
@@ -234,7 +240,7 @@
     public static int   PLAYER_RATE_DROP_ITEM;
     public static int   PLAYER_RATE_DROP_EQUIP;    
     public static int   PLAYER_RATE_DROP_EQUIP_WEAPON;    
-    
+
 	/** Pet Rates (Multipliers) */ 	
 	public static float         PET_XP_RATE; 
  	public static int           PET_FOOD_RATE;
@@ -322,7 +328,7 @@
     public static final String  HEXID_FILE					= "./config/hexid.txt";
     public static final String  COMMAND_PRIVILEGES_FILE     = "./config/command-privileges.properties";
     public static final String  AI_FILE     				= "./config/ai.properties";
-	    
+    
     public static boolean CHECK_KNOWN;
     
     public static int     GAME_SERVER_LOGIN_PORT;
@@ -577,7 +583,7 @@
 	            PLAYER_RATE_DROP_ITEM           = Integer.parseInt(serverSettings.getProperty("PlayerRateDropItem", "70"));
 	            PLAYER_RATE_DROP_EQUIP          = Integer.parseInt(serverSettings.getProperty("PlayerRateDropEquip", "25"));
 	            PLAYER_RATE_DROP_EQUIP_WEAPON   = Integer.parseInt(serverSettings.getProperty("PlayerRateDropEquipWeapon", "5"));
-	            
+                
 	            PET_XP_RATE     = Float.parseFloat(serverSettings.getProperty("PetXpRate", "1."));
 	            PET_FOOD_RATE   = Integer.parseInt(serverSettings.getProperty("PetFoodRate", "1")); 
                 
@@ -834,6 +840,7 @@
                 GM_NAME_COLOUR = Integer.decode("0x" + otherSettings.getProperty("GMNameColour", "00FF00"));
                 GM_STARTUP_INVISIBLE = Boolean.parseBoolean(otherSettings.getProperty("GMStartupInvisible", "True"));
                 GM_STARTUP_SILENCE = Boolean.parseBoolean(otherSettings.getProperty("GMStartupSilence", "True"));
+                
 	        }
 	        catch (Exception e)
 	        {
@@ -873,13 +880,15 @@
 	            
 	            ALT_GAME_TIREDNESS      = Boolean.parseBoolean(altSettings.getProperty("AltGameTiredness", "false"));
 	            ALT_GAME_CREATION       = Boolean.parseBoolean(altSettings.getProperty("AltGameCreation", "false"));
-	            ALT_GAME_CREATION_SPEED = Integer.parseInt(altSettings.getProperty("AltGameCreationSpeed", "10"));
+	            ALT_GAME_CREATION_SPEED = Double.parseDouble(altSettings.getProperty("AltGameCreationSpeed", "1"));
+	            ALT_GAME_CREATION_XP_RATE=Double.parseDouble(altSettings.getProperty("AltGameCreationXpRate", "1"));
+	            ALT_GAME_CREATION_SP_RATE=Double.parseDouble(altSettings.getProperty("AltGameCreationSpRate", "1"));
 	            ALT_GAME_SKILL_LEARN    = Boolean.parseBoolean(altSettings.getProperty("AltGameSkillLearn", "false"));
 	            ALT_GAME_CANCEL_BOW     = altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("bow") || altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("all");
 	            ALT_GAME_CANCEL_CAST    = altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("cast") || altSettings.getProperty("AltGameCancelByHit", "Cast").equalsIgnoreCase("all");
 	            ALT_GAME_SHIELD_BLOCKS  = Boolean.parseBoolean(altSettings.getProperty("AltShieldBlocks", "false"));
 	            ALT_GAME_DELEVEL        = Boolean.parseBoolean(altSettings.getProperty("Delevel", "true"));
-            	    ALT_GAME_MAGICFAILURES  = Boolean.parseBoolean(altSettings.getProperty("MagicFailures", "false"));
+            	ALT_GAME_MAGICFAILURES  = Boolean.parseBoolean(altSettings.getProperty("MagicFailures", "false"));
 	            ALT_GAME_MOB_ATTACK_AI  = Boolean.parseBoolean(altSettings.getProperty("AltGameMobAttackAI", "false"));
 	            ALT_GAME_SKILL_FORMULAS = altSettings.getProperty("AltGameSkillFormulas", "none");
 	            ALT_GAME_EXPONENT_XP    = Float.parseFloat(altSettings.getProperty("AltGameExponentXp", "0."));
@@ -1232,7 +1241,9 @@
         // Alternative settings
         else if (pName.equalsIgnoreCase("AltGameTiredness")) ALT_GAME_TIREDNESS = Boolean.valueOf(pValue);
         else if (pName.equalsIgnoreCase("AltGameCreation")) ALT_GAME_CREATION = Boolean.valueOf(pValue);
-        else if (pName.equalsIgnoreCase("AltGameCreationSpeed")) ALT_GAME_CREATION_SPEED = Integer.parseInt(pValue);
+        else if (pName.equalsIgnoreCase("AltGameCreationSpeed")) ALT_GAME_CREATION_SPEED = Double.parseDouble(pValue);
+        else if (pName.equalsIgnoreCase("AltGameCreationXpRate")) ALT_GAME_CREATION_XP_RATE = Double.parseDouble(pValue);
+        else if (pName.equalsIgnoreCase("AltGameCreationSpRate")) ALT_GAME_CREATION_SP_RATE = Double.parseDouble(pValue);
         else if (pName.equalsIgnoreCase("AltGameSkillLearn")) ALT_GAME_SKILL_LEARN = Boolean.valueOf(pValue);
 
         else if (pName.equalsIgnoreCase("AltGameCancelByHit"))
Index: net/sf/l2j/gameserver/RecipeController.java
===================================================================
--- net/sf/l2j/gameserver/RecipeController.java	(revision 1682)
+++ net/sf/l2j/gameserver/RecipeController.java	(working copy)
@@ -33,8 +33,6 @@
 import javolution.util.FastList;
 import javolution.util.FastMap;
 import net.sf.l2j.Config;
-import net.sf.l2j.gameserver.ClientScheduler;
-import net.sf.l2j.gameserver.GameTimeController;
 import net.sf.l2j.gameserver.lib.Rnd;
 import net.sf.l2j.gameserver.model.Inventory;
 import net.sf.l2j.gameserver.model.L2ItemInstance;
@@ -57,51 +55,49 @@
 public class RecipeController
 {
 	protected static Logger _log = Logger.getLogger(RecipeController.class.getName());
-
+	
 	private static RecipeController _instance;
 	private Map<Integer, L2RecipeList> _lists;
 	protected static Map<L2PcInstance, RecipeItemMaker> activeMakers = Collections.synchronizedMap(new WeakHashMap<L2PcInstance, RecipeItemMaker>());
 	protected static final Random _rnd = new Random();
-
+	
 	public static RecipeController getInstance()
 	{
 		return _instance == null ? _instance = new RecipeController() : _instance;
 	}
-
+	
 	public RecipeController()
 	{
 		_lists = new FastMap<Integer, L2RecipeList>();
 		String line = null;
 		LineNumberReader lnr = null;
-
+		
 		try
 		{
 			File recipesData = new File(Config.DATAPACK_ROOT, "data/recipes.csv");
 			lnr = new LineNumberReader(new BufferedReader(new FileReader(recipesData)));
-
+			
 			while ((line = lnr.readLine()) != null)
 			{
 				if (line.trim().length() == 0 || line.startsWith("#"))
-				{
 					continue;
-				}
-
+				
 				parseList(line);
-
+				
 			}
 			_log.config("RecipeController: Loaded " + _lists.size() + " Recipes.");
 		}
 		catch (Exception e)
 		{
 			if (lnr != null)
-			{
+
 				_log.log(Level.WARNING, "error while creating recipe controller in linenr: "
-					+ lnr.getLineNumber(), e);
-			}
+				         + lnr.getLineNumber(), e);
+
 			else
-			{
+
 				_log.warning("No recipes were found in data folder");
-			}
+
 		}
 		finally
 		{
@@ -114,17 +110,17 @@
 			}
 		}
 	}
-
+	
 	public int getRecipesCount()
 	{
 		return _lists.size();
 	}
-
+	
 	public L2RecipeList getRecipeList(int listId)
 	{
 		return _lists.get(listId);
 	}
-
+	
 	public L2RecipeList getRecipeByItemId(int itemId)
 	{
 		for (int i = 0; i < _lists.size(); i++)
@@ -137,112 +133,118 @@
 		}
 		return null;
 	}
-
+	
 	public synchronized void requestBookOpen(L2PcInstance player, boolean isDwarvenCraft)
 	{
 		RecipeItemMaker maker = null;
 		if (Config.ALT_GAME_CREATION) maker = activeMakers.get(player);
-
+		
 		if (maker == null)
 		{
 			RecipeBookItemList response = new RecipeBookItemList(isDwarvenCraft, player.getMaxMp());
 			response.addRecipes(isDwarvenCraft	? player.getDwarvenRecipeBook()
-												: player.getCommonRecipeBook());
+			                                  	: player.getCommonRecipeBook());
 			player.sendPacket(response);
 			return;
 		}
-
+		
 		SystemMessage sm = new SystemMessage(SystemMessage.CANT_ALTER_RECIPEBOOK_WHILE_CRAFTING);
 		player.sendPacket(sm);
 		return;
 	}
-
+	
 	public synchronized void requestMakeItemAbort(L2PcInstance player)
 	{
-		activeMakers.remove(player);
+		if (activeMakers != null) activeMakers.remove(player);
 	}
-
+	
 	public synchronized void requestManufactureItem(L2PcInstance manufacturer, int recipeListId,
-													L2PcInstance player)
+	                                                L2PcInstance player)
 	{
 		L2RecipeList recipeList = getValidRecipeList(player, recipeListId);
-
+		
 		if (recipeList == null) return;
-		manufacturer.isInCraftMode(true);
-
-		if (!Config.ALT_GAME_CREATION)
+		
+		RecipeItemMaker maker;
+		
+		if (Config.ALT_GAME_CREATION && (maker = activeMakers.get(manufacturer)) != null) // check if busy
 		{
-			new RecipeItemMaker(manufacturer, recipeList, player);
+			player.sendMessage("Manufacturer is busy, please try later.");
+			return;
 		}
-		else
+		
+		maker = new RecipeItemMaker(manufacturer, recipeList, player);
+		if (maker.isValid)
 		{
-			RecipeItemMaker maker = activeMakers.get(manufacturer);
-			if (maker != null)
+			if (Config.ALT_GAME_CREATION)
 			{
-				player.sendMessage("Manufacturer is busy creating.");
-				manufacturer.isInCraftMode(false);
-				return;
+				activeMakers.put(manufacturer, maker);
+				ClientScheduler.scheduleEvent(maker, 100);
 			}
-			maker = new RecipeItemMaker(manufacturer, recipeList, player);
-			if (maker.isValid) activeMakers.put(manufacturer, maker);
+			else maker.run();
 		}
 	}
-
+	
 	public synchronized void requestMakeItem(L2PcInstance player, int recipeListId)
 	{
 		L2RecipeList recipeList = getValidRecipeList(player, recipeListId);
-
-		if (recipeList == null) return;
-
-		player.isInCraftMode(true);
-
-		if (!Config.ALT_GAME_CREATION)
+		
+		if (recipeList == null)
 		{
-			new RecipeItemMaker(player, recipeList, player);
+			_log.warning("recipelist == null");
+			return;
 		}
-		else
+		
+		RecipeItemMaker maker;
+		
+		// check if already busy (possible in alt mode only)
+		if (Config.ALT_GAME_CREATION && ((maker = activeMakers.get(player)) != null)) 
 		{
-			RecipeItemMaker maker = activeMakers.get(player);
-			if (maker != null)
+			SystemMessage sm = new SystemMessage(614);
+			sm.addString("You are busy creating ");
+			sm.addItemName(recipeList.getItemId());
+			player.sendPacket(sm);
+			return;
+		}
+		
+		maker = new RecipeItemMaker(player, recipeList, player);
+		if (maker.isValid)
+		{
+			if (Config.ALT_GAME_CREATION)
 			{
-				SystemMessage sm = new SystemMessage(614);
-				sm.addString("You are busy creating ");
-				sm.addItemName(recipeList.getItemId());
-				player.sendPacket(sm);
-				player.isInCraftMode(false);
-				return;
+				activeMakers.put(player, maker);
+				ClientScheduler.scheduleEvent(maker, 100);
 			}
-			maker = new RecipeItemMaker(player, recipeList, player);
-			if (maker.isValid) activeMakers.put(player, maker);
+			else maker.run();
 		}
 	}
-
+	
 	private void parseList(String line)
 	{
 		try
 		{
 			StringTokenizer st = new StringTokenizer(line, ";");
 			List<L2RecipeInstance> recipePartList = new FastList<L2RecipeInstance>();
-
+			
 			//we use common/dwarf for easy reading of the recipes.csv file 
 			String recipeTypeString = st.nextToken();
-
-			//now we parse the string into a boolean 
+			
+			// now parse the string into a boolean 
 			boolean isDwarvenRecipe;
-
+			
 			if (recipeTypeString.equalsIgnoreCase("dwarven")) isDwarvenRecipe = true;
 			else if (recipeTypeString.equalsIgnoreCase("common")) isDwarvenRecipe = false;
 			else
 			{ //prints a helpfull message 
-				_log.warning("Error parsing recipes.csv, unknow recipe type " + recipeTypeString);
+				_log.warning("Error parsing recipes.csv, unknown recipe type " + recipeTypeString);
 				return;
 			}
-
+			
 			String recipeName = st.nextToken();
 			int id = Integer.parseInt(st.nextToken());
 			int recipeId = Integer.parseInt(st.nextToken());
 			int level = Integer.parseInt(st.nextToken());
-
+			
 			//material
 			StringTokenizer st2 = new StringTokenizer(st.nextToken(), "[],");
 			while (st2.hasMoreTokens())
@@ -253,18 +255,18 @@
 				L2RecipeInstance rp = new L2RecipeInstance(rpItemId, quantity);
 				recipePartList.add(rp);
 			}
-
+			
 			int itemId = Integer.parseInt(st.nextToken());
 			int count = Integer.parseInt(st.nextToken());
-
+			
 			//npc fee
 			/*String notdoneyet = */st.nextToken();
-
+			
 			int mpCost = Integer.parseInt(st.nextToken());
 			int successRate = Integer.parseInt(st.nextToken());
-
+			
 			L2RecipeList recipeList = new L2RecipeList(id, level, recipeId, recipeName, successRate,
-														mpCost, itemId, count, isDwarvenRecipe);
+			                                           mpCost, itemId, count, isDwarvenRecipe);
 			for (L2RecipeInstance recipePart : recipePartList)
 			{
 				recipeList.addRecipe(recipePart);
@@ -275,328 +277,490 @@
 		{
 			_log.severe("Exception in RecipeController.parseList() - " + e);
 		}
-		;
 	}
-
+	
 	public class RecipeItemMaker implements Runnable
 	{
 		public boolean isValid;
-		final List<L2ItemInstance> items;
-		int materialsRefPrice;
-		final L2PcInstance player;
+		List<TempItem> items = null;
+		final L2RecipeList recipeList;
+		final L2PcInstance player; // "crafter"
+		final L2PcInstance target; // "customer"		
+		final L2Skill skill;
+		final int skillId;
+		final int skillLevel;
+		double creationPasses;
 		int price;
-		final L2RecipeList recipeList;
-		final L2PcInstance target;
-		int timeReady;
 		int delay;
-		int gameTicks;
 		int totalItems;
-		int usedItems;
-		int skillLevel;
+		int materialsRefPrice;
+		double manaRequired;
 		
 		public RecipeItemMaker(L2PcInstance player, L2RecipeList recipeList, L2PcInstance target)
 		{
 			this.player = player;
 			this.target = target;
 			this.recipeList = recipeList;
-			this.items = new FastList<L2ItemInstance>();
-			this.isValid = false;
-
-			skillLevel = recipeList.isDwarvenRecipe()	? player.getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN)
-														: player.getSkillLevel(L2Skill.SKILL_CREATE_COMMON);
-
-			if (!validateSkillLevel()) return;
-			if (!validateRecipeList()) return;
-			if (!validateCustomerCanAfford(target,player)) return; 
-			if (!validateMaterials()) return;
-			if (!validateMp()) return;
-
-			isValid = true;
-			updateTime();
-			run();
-		}
-
-		private void finishCrafting()
-		{
-			player.reduceCurrentMp(recipeList.getMpCost());
-
-			if (Rnd.get(100) < recipeList.getSuccessRate())
+			
+			isValid = false;
+			skillId = recipeList.isDwarvenRecipe()	? L2Skill.SKILL_CREATE_DWARVEN
+			                                      	: L2Skill.SKILL_CREATE_COMMON;
+			skillLevel = player.getSkillLevel(skillId);
+			skill = player.getKnownSkill(skillId);
+			
+			player.isInCraftMode(true);
+			
+			if (player.isAlikeDead())
 			{
-				if (target != player)
-				{
-					if (price > 0)
+				player.sendMessage("Dead persons can't craft.");
+				player.sendPacket(new ActionFailed());
+				abort();
+				return;
+			}
+			
+			if (target.isAlikeDead())
+			{
+				target.sendMessage("Dead customers can't use manufacture.");
+				target.sendPacket(new ActionFailed());
+				abort();
+				return;
+			}
+			
+			// validate recipe list
+			if ((recipeList == null) || (recipeList.getRecipes().length == 0))
+			{
+				player.sendMessage("No such recipe");
+				player.sendPacket(new ActionFailed());
+				abort();
+				return;
+			}
+			
+			manaRequired = recipeList.getMpCost();
+			
+			// validate skill level
+			if (recipeList.getLevel() > skillLevel)
+			{
+				player.sendMessage("Need skill level " + recipeList.getLevel());
+				player.sendPacket(new ActionFailed());
+				abort();
+				return;
+			}
+			
+			// check that customer can afford to pay for creation services
+			if (player != target)
+			{
+				for (L2ManufactureItem temp : player.getCreateList().getList())
+					if (temp.getRecipeId() == recipeList.getId()) // find recipe for item we want manufactured
 					{
-						target.reduceAdena("Manufacture", price, player, false);
-						player.addAdena("Manufacture", price, target, false);
+						price = temp.getCost();
+						if (target.getAdena() < price) // check price
+						{
+							target.sendPacket(new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA));
+							abort();
+							return;
+						}
+						break;
 					}
-					updateCurLoad();
+			}
+			
+			// make temporary items
+			if ((items = listItems(false)) == null) 
+				{
+					abort();
+					return;
 				}
-
-				RewardPlayer();
-				updateMakeInfo(true); // success
+			
+			// calculate reference price
+			for (TempItem i : items)
+			{
+				materialsRefPrice += i.getReferencePrice() * i.getQuantity();
+				totalItems += i.getQuantity();
 			}
-			else
+			// initial mana check requires MP as written on recipe
+			if (player.getCurrentMp() < manaRequired)
 			{
-				player.sendMessage("Item(s) failed to create");
-				updateMakeInfo(false);
+				target.sendPacket(new SystemMessage(SystemMessage.NOT_ENOUGH_MP));
+				abort();
+				return;
 			}
-			activeMakers.remove(player);
+			
+			// determine number of creation passes needed
+			// can "equip"  skillLevel items each pass
+			creationPasses = (totalItems / skillLevel) + ((totalItems % skillLevel)!=0 ? 1 : 0);
+			
+			if (Config.ALT_GAME_CREATION && creationPasses != 0) // update mana required to "per pass"
+				manaRequired /= creationPasses; // checks to validateMp() will only need portion of mp for one pass
+			
+			updateMakeInfo(true); // attempt to update mana bar
+			updateCurMp();
+			updateCurLoad();
+			
 			player.isInCraftMode(false);
-
-			target.sendPacket(new ItemList(target, false));
+			isValid = true;
 		}
-
+		
 		public void run()
 		{
-			player.isInCraftMode(true);
-			gameTicks = GameTimeController.getGameTicks();
-			if (!validateCraftingEnabled() || !validateMp()) return;
+			if (!Config.IS_CRAFTING_ENABLED)
+			{
+				target.sendMessage("Crafting is currently disabled.");
+				abort();
+				return;
+			}
 
-			updateTime();
+			if (player == null || target == null)
+			{
+				_log.warning("player or target == null (disconnected?), aborting");
+				abort();
+				return;
+			}
 
+			if (player.isOnline()==0 || target.isOnline()==0)
+			{
+				_log.warning("player or target is not online, aborting");
+				abort();
+				return;
+			}
+
+			if (Config.ALT_GAME_CREATION && activeMakers.get(player) == null)
+			{
+				player.sendMessage("Crafting aborted");
+				abort();
+				return;
+			}		
+			
+			// check mana
+			if (!validateMp()) return;
+			
+			// divided by RATE_CONSUMABLES_COST to remove craft time increase on higher consumable rates 
+			// to prevent slower crafting on higher consumable rates
+			delay = (int) (Config.ALT_GAME_CREATION_SPEED * player.getMReuseRate(skill)
+					* GameTimeController.TICKS_PER_SECOND / Config.RATE_CONSUMABLE_COST)
+					* GameTimeController.MILLIS_IN_TICK;
+			
 			if (Config.ALT_GAME_CREATION && !items.isEmpty())
 			{
-				player.reduceCurrentMp(recipeList.getMpCost()); // use some mp
+				player.reduceCurrentMp(manaRequired); // use some mp
 				grabSomeItems(); // grab (equip) some more items with a nice msg to player
-
-				MagicSkillUser msk = new MagicSkillUser(
-														player,
-														recipeList.isDwarvenRecipe() ? L2Skill.SKILL_CREATE_DWARVEN
-																					: L2Skill.SKILL_CREATE_COMMON,
-														skillLevel, delay, 0);
-
+				
+				// FIXME: please fix this packet to show crafting animation (somebody)
+				MagicSkillUser msk = new MagicSkillUser(player, skillId, skillLevel, delay, 0);
 				player.broadcastPacket(msk);
-
+				
 				player.sendPacket(new SetupGauge(0, delay));
+				
+				ClientScheduler.scheduleEvent(this, 100 + delay);
+				_log.warning(".");
+			}
+			else
+				// finish crafting 
+			{
+				_log.warning("finishcrafting entered");
+				if(!Config.ALT_GAME_CREATION) player.reduceCurrentMp(manaRequired);
+				
+				// first take adena for manufacture
+				if ((target != player) && price > 0) // customer must pay for services
+				{
+					// attempt to pay for item
+					L2ItemInstance adenatransfer = target.transferItem("PayManufacture",
+											target.getInventory().getAdenaInstance().getObjectId(),
+											price, player.getInventory(), player);
+					
+					if(adenatransfer==null || adenatransfer.getCount()!=price)
+					{
+						target.sendPacket(new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA));
+						abort();
+						return;	
+					}
+				}
 
-				ClientScheduler.getInstance().scheduleLow(this, 100 + delay);
+				_log.warning("calling listItems(true)");
+				if ((items = listItems(true)) == null) // this line actually takes materials from inventory
+				{
+					_log.warning("Could not take materials from inventory: " + target);
+					target.sendMessage("Could not take materials from inventory");
+				}
+				else if (Rnd.get(100) < recipeList.getSuccessRate())
+				{
+					RewardPlayer(); // and this one immediately puts created item in its place		
+					updateMakeInfo(true);
+				}
+				else
+				{
+					player.sendMessage("Item(s) failed to create");
+					updateMakeInfo(false);
+				}
+				_log.warning("before updates and finish");
+				// update load and mana bar of craft window
+				updateCurMp();
+				updateCurLoad();				
+				activeMakers.remove(player);
+				player.isInCraftMode(false);
+				target.sendPacket(new ItemList(target, false));
 			}
-			else finishCrafting();
-
-			// update load and mana bar of craft window
-			updateMakeInfo(true);
-			updateCurMp();
-			updateCurLoad();
 		}
-
-		private void updateTime()
-		{
-			// divided by RATE_CONSUMABLES_COST to remove craft time increase on higher consumable rates (more mats consumed -> more time)
-			timeReady = gameTicks
-				+ (int) (Config.ALT_GAME_CREATION_SPEED
-					* player.getMReuseRate(player.getKnownSkill(172))
-					* GameTimeController.TICKS_PER_SECOND / Config.RATE_CONSUMABLE_COST);
-
-			delay = (timeReady - gameTicks) * GameTimeController.MILLIS_IN_TICK;
-		}
-
+		
 		private void updateMakeInfo(boolean success)
 		{
-			if (target == player) target.sendPacket(new RecipeItemMakeInfo(recipeList.getId(), target, success));
+			if (target == player) target.sendPacket(new RecipeItemMakeInfo(recipeList.getId(), target,
+			                                                               success));
 			else target.sendPacket(new RecipeShopItemInfo(player.getObjectId(), recipeList.getId()));
 		}
-
+		
 		private void updateCurLoad()
 		{
 			StatusUpdate su = new StatusUpdate(target.getObjectId());
 			su.addAttribute(StatusUpdate.CUR_LOAD, target.getCurrentLoad());
 			target.sendPacket(su);
 		}
-
+		
 		private void updateCurMp()
 		{
-
+			
 			StatusUpdate su = new StatusUpdate(target.getObjectId());
 			su.addAttribute(StatusUpdate.CUR_MP, (int) target.getCurrentMp());
 			target.sendPacket(su);
 		}
-
+		
 		private void grabSomeItems()
 		{
-			int numItems = player.getSkillLevel(172);
+			int numItems = skillLevel;
+			
 			while (numItems > 0 && !items.isEmpty())
 			{
-				L2ItemInstance item = items.get(0);
-
-				int count = item.getCount();
+				TempItem item = items.get(0);
+				
+				int count = item.getQuantity();
 				if (count >= numItems) count = numItems;
-
-				item.setCount(item.getCount() - count);
-				if (item.getCount() <= 0) items.remove(0);
-
+				
+				item.setQuantity(item.getQuantity() - count);
+				if (item.getQuantity() <= 0) items.remove(0);
+				else items.set(0, item);
+				
 				numItems -= count;
-				usedItems += count;
-
-				SystemMessage sm = new SystemMessage(368); // you equipped ...
-				sm.addNumber(count);
-				sm.addItemName(item.getItemId());
-				if (target == null) player.sendPacket(sm);
-				else target.sendPacket(sm);
+				
+				if (target == player)
+				{
+					SystemMessage sm = new SystemMessage(368); // you equipped ...
+					sm.addNumber(count);
+					sm.addItemName(item.getItemId());
+					player.sendPacket(sm);
+				} 
+				else target.sendMessage("Manufacturer " + player.getName() + " used " + count + " "
+				                        + item.getItemName());
 			}
 		}
-
-		private boolean validateCraftingEnabled()
+		
+		private boolean validateMp()
 		{
-			if (!Config.IS_CRAFTING_ENABLED)
+			if (player.getCurrentMp() < manaRequired)
 			{
-				target.sendMessage("Crafting is currently disabled.");
-				player.isInCraftMode(false);
-				activeMakers.remove(player);
-				updateMakeInfo(false);
-				return false;
-			}
-			return true;
-		}
-
-		private boolean validateCustomerCanAfford(L2PcInstance customer, L2PcInstance manufacturer)
-		{
-			if(customer==manufacturer) return true;
-			for (L2ManufactureItem temp : manufacturer.getCreateList().getList())
-				if (temp.getRecipeId() == recipeList.getId()) // find recipe for item we want manufactured
+				// rest (wait for MP)
+				if (Config.ALT_GAME_CREATION)
 				{
-					int price = temp.getCost();
-					if (customer.getAdena() < price) // check price
-					{
-						customer.sendPacket(new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA));
-						manufacturer.isInCraftMode(false);
-						activeMakers.remove(manufacturer);
-						return false;
-					}
-					break;
+					player.sendPacket(new SetupGauge(0, delay));
+					ClientScheduler.scheduleEvent(this, 100 + delay);
 				}
-			return true;
-		}		
-		private boolean validateMp()
-		{
-			if (player.getCurrentMp() < recipeList.getMpCost())
-			{
-				target.sendPacket(new SystemMessage(SystemMessage.NOT_ENOUGH_MP));
-				player.isInCraftMode(false);
-				activeMakers.remove(player);
-				updateMakeInfo(false);
+				else
+					// no rest  - report no mana
+				{
+					target.sendPacket(new SystemMessage(SystemMessage.NOT_ENOUGH_MP));
+					abort(); // false == don't resume
+				}
 				return false;
 			}
 			return true;
 		}
-
-		private boolean validateMaterials()
+		
+		private List<TempItem> listItems(boolean remove)
 		{
 			L2RecipeInstance[] recipes = recipeList.getRecipes();
-
 			Inventory inv = target.getInventory();
-
+			List<TempItem> materials = new FastList<TempItem>();
+			
 			for (L2RecipeInstance recipe : recipes)
 			{
-				if (recipe.getQuantity() != 0)
+				int quantity = recipeList.isConsumable() ? (int) (recipe.getQuantity() * Config.RATE_CONSUMABLE_COST)
+				                                         : (int) recipe.getQuantity();
+				
+				if (quantity > 0)
 				{
-					L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId());
-					if ((invItem == null)
-						|| ((recipeList.isConsumable()	? (int) (recipe.getQuantity() * Config.RATE_CONSUMABLE_COST)
-														: recipe.getQuantity()) > invItem.getCount()))
+					L2ItemInstance item = inv.getItemByItemId(recipe.getItemId());
+					
+					// now we verify that we have enough materials
+					if (item==null || item.getCount() < quantity)
 					{
 						target.sendMessage("You dont have the right elements for making this item"
-							+ ((recipeList.isConsumable() && Config.RATE_CONSUMABLE_COST != 1)	? ".\nDue to server rates you need "
-																									+ Config.RATE_CONSUMABLE_COST
-																									+ "x more material than listed in recipe"
-																								: ""));
-						player.isInCraftMode(false);
-						activeMakers.remove(player);
-						updateMakeInfo(false);
-						return false;
+						                   + ((recipeList.isConsumable() && Config.RATE_CONSUMABLE_COST != 1)	? ".\nDue to server rates you need "
+						                                                                                     	  + Config.RATE_CONSUMABLE_COST
+						                                                                                     	  + "x more material than listed in recipe"
+						                                                                                     	  : ""));
+						abort();
+						return null;
 					}
+					
+					// make new temporary object, just for counting puroses, real item modification only
+					// on finishCrafting() so we minimize risk of losing items
+					
+					TempItem temp = new TempItem(item, quantity);
+					materials.add(temp);
 				}
 			}
 
-			for (L2RecipeInstance recipe : recipes)
+			if (remove)
 			{
-				if (recipe.getQuantity() != 0)
-				{
-					L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId());
-					invItem = inv.dropItem(
-											"Manufacture",
-											invItem.getObjectId(),
-											recipeList.isConsumable()	? (int) (recipe.getQuantity() * Config.RATE_CONSUMABLE_COST)
-																		: recipe.getQuantity(), target,
-											player);
-					items.add(invItem);
-					materialsRefPrice += invItem.getReferencePrice() * invItem.getCount();
-					totalItems += invItem.getCount();
-				}
-			}
-
-			return true;
+				_log.warning("item removal requested: ");
+				for(TempItem tmp : materials)
+					{
+					_log.warning("removed "+tmp.getQuantity()+" "+tmp.getItemName()+" from inventory");
+					inv.destroyItemByItemId("Manufacture", tmp.getItemId(), tmp.getQuantity(), target,
+					                        player);
+					}
+			}			
+			return materials;
 		}
-
-		private boolean validateSkillLevel()
+		
+		private void abort()
 		{
-			if (recipeList.getLevel() > skillLevel)
+			updateMakeInfo(false);
+			player.isInCraftMode(false);
+			activeMakers.remove(player);
+		}
+		
+		/**
+		 * TODO: This class should be in some other file, but I don't know where 
+		 * 
+		 * Class explanation:
+		 * Use it for item counting or checking purposes. Any place you don't want to touch inventory 
+		 * class contains itemId, quantity, ownerId, referencePrice, but not objectId 
+		 */
+		private class TempItem
+		{ // no object id stored, this will be only "list" of items with it's owner
+			private int _itemId;
+			private int _quantity;
+			private int _ownerId;
+			private int _referencePrice;
+			private String _itemName;
+			
+			/**
+			 * @param item
+			 * @param quantity of that item
+			 */
+			public TempItem(L2ItemInstance item, int quantity)
 			{
-				player.sendMessage("Need skill level " + recipeList.getLevel());
-				player.sendPacket(new ActionFailed());
-				player.isInCraftMode(false);
-				activeMakers.remove(player);
-				updateMakeInfo(false);
-				return false;
+				super();
+				_itemId = item.getItemId();
+				_quantity = quantity;
+				_ownerId = item.getOwnerId();
+				_itemName = item.getItem().getName();
+				_referencePrice = item.getReferencePrice();
 			}
-			return true;
-		}
-
-		private boolean validateRecipeList()
-		{
-			if ((recipeList == null) || (recipeList.getRecipes().length == 0))
+			
+			/**
+			 * @return Returns the quantity.
+			 */
+			public int getQuantity()
 			{
-				player.sendMessage("No such recipe");
-				player.isInCraftMode(false);
-				activeMakers.remove(player);
-				updateMakeInfo(false);
-				return false;
+				return _quantity;
 			}
-			return true;
+			
+			/**
+			 * @param quantity The quantity to set.
+			 */
+			public void setQuantity(int quantity)
+			{
+				_quantity = quantity;
+			}
+			
+			public int getReferencePrice()
+			{
+				return _referencePrice;
+			}
+			
+			/**
+			 * @return Returns the itemId.
+			 */
+			public int getItemId()
+			{
+				return _itemId;
+			}
+			
+			/**
+			 * @return Returns the ownerId.
+			 */
+			public int getOwnerId()
+			{
+				return _ownerId;
+			}
+			
+			/**
+			 * @return Returns the itemName.
+			 */
+			public String getItemName()
+			{
+				return _itemName;
+			}
 		}
-
+		
 		private void RewardPlayer()
 		{
 			int itemId = recipeList.getItemId();
 			int itemCount = recipeList.getCount();
-
+			
 			L2ItemInstance createdItem = target.getInventory().addItem("Manufacture", itemId, itemCount,
-																		target, player);
+			                                                           target, player);
+			
+			// inform customer of earned item
 			SystemMessage sm = new SystemMessage(SystemMessage.EARNED_ITEM);
 			sm.addItemName(itemId);
 			sm.addNumber(itemCount);
 			target.sendPacket(sm);
-
+			
+			if (target != player)
+			{
+				// inform manufacturer of earned profit
+				sm = new SystemMessage(SystemMessage.EARNED_ADENA);
+				sm.addNumber(price);
+				player.sendPacket(sm);
+			}
+			
 			if (Config.ALT_GAME_CREATION)
 			{
 				int recipeLevel = recipeList.getLevel();
 				int exp = createdItem.getReferencePrice() * itemCount;
 				// one variation
-				// exp -= materialsRefPrice;
 				
+				// exp -= materialsRefPrice;   // mat. ref. price is not accurate so other method is better
+				
 				if (exp < 0) exp = 0;
 				
 				// another variation
 				exp /= recipeLevel;
-				for (int i = skillLevel; i > recipeLevel; i--) exp /= 4;
+				for (int i = skillLevel; i > recipeLevel; i--)
+					exp /= 4;
 				
 				int sp = exp / 10;
-				player.addExpAndSp((int) player.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_XP, null,
-															null),
-									(int) player.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_SP, null,
-															null));
-
-				sm = new SystemMessage(SystemMessage.YOU_EARNED_S1_EXP_AND_S2_SP);
-				sm.addNumber((int) player.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_XP, null, null));
-				sm.addNumber((int) player.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_SP, null, null));
-				player.sendPacket(sm);
+				 
+				// FIXME: Added multiplication of Creation speed with XP/SP gain
+				// slower crafting -> more XP,  faster crafting -> less XP 
+				// admins:  find balance you like ... you can use ALT_GAME_CREATION_RATE_XP/SP to
+				// compensate XP/SP (default = 1)   
+				// goal is to make ALT_GAME_CREATION
+				// a bit slower, bit more interesting, and give some xp/sp but not too much
+				
+				player.addExpAndSp((int) player.calcStat(Stats.EXPSP_RATE, exp * Config.ALT_GAME_CREATION_XP_RATE  
+				                                         * Config.ALT_GAME_CREATION_SPEED, null, null)
+				                  ,(int) player.calcStat(Stats.EXPSP_RATE, sp * Config.ALT_GAME_CREATION_SP_RATE   
+				                                         * Config.ALT_GAME_CREATION_SPEED, null, null));
 			}
+			updateMakeInfo(true); // success
 		}
 	}
-
+	
 	private L2RecipeList getValidRecipeList(L2PcInstance player, int id)
 	{
 		L2RecipeList recipeList = getRecipeList(id - 1);
-
+		
 		if ((recipeList == null) || (recipeList.getRecipes().length == 0))
 		{
 			player.sendMessage("No recipe for: " + id);
@@ -604,8 +768,5 @@
 			return null;
 		}
 		return recipeList;
-	};
-	
-
+	}
 }
-