All pastes #45022 Raw Edit

Something

public text v1 · immutable
#45022 ·published 2006-03-09 11:59 UTC
rendered paste body
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */
package net.sf.l2j.gameserver;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javolution.util.FastList;
import javolution.util.FastMap;
import net.sf.l2j.Config;
import net.sf.l2j.gameserver.lib.Rnd;
import net.sf.l2j.gameserver.model.Inventory;
import net.sf.l2j.gameserver.model.L2ItemInstance;
import net.sf.l2j.gameserver.model.L2ManufactureItem;
import net.sf.l2j.gameserver.model.L2RecipeInstance;
import net.sf.l2j.gameserver.model.L2RecipeList;
import net.sf.l2j.gameserver.model.L2Skill;
import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
import net.sf.l2j.gameserver.serverpackets.ActionFailed;
import net.sf.l2j.gameserver.serverpackets.ItemList;
import net.sf.l2j.gameserver.serverpackets.MagicSkillUser;
import net.sf.l2j.gameserver.serverpackets.RecipeBookItemList;
import net.sf.l2j.gameserver.serverpackets.RecipeItemMakeInfo;
import net.sf.l2j.gameserver.serverpackets.RecipeShopItemInfo;
import net.sf.l2j.gameserver.serverpackets.SetupGauge;
import net.sf.l2j.gameserver.serverpackets.StatusUpdate;
import net.sf.l2j.gameserver.serverpackets.SystemMessage;
import net.sf.l2j.gameserver.skills.Stats;

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, ReceipeItemMaker> activeMakers = Collections.synchronizedMap(new WeakHashMap<L2PcInstance,ReceipeItemMaker>());
	
    protected static final Random _rnd = new Random();
	
	public static RecipeController getInstance()
	{
		if (_instance == null)
		{
			_instance = new RecipeController();
		}
		return _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);
			}
			else
			{
				_log.warning("No recipes were found in data folder");
			}
		}
        finally
        {
            try { lnr.close(); } catch (Exception e) { }
        }
	}
	
	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++)
		{
			L2RecipeList find = _lists.get(new Integer(i));
			if (find.getRecipeId() == itemId)
			{
				return find;
			}
		}
		return null;
	}
	
	public synchronized void requestBookOpen(L2PcInstance player, boolean isDwarvenCraft)
	{						
		if (!Config.ALT_GAME_CREATION){
			RecipeBookItemList response = new RecipeBookItemList(isDwarvenCraft,player.getMaxMp()); 
		 	if (isDwarvenCraft) 
		 		response.addRecipes(player.getDwarvenRecipeBook()); 
		 	else 
		 		response.addRecipes(player.getCommonRecipeBook()); 
			player.sendPacket(response);
			return;
		}
        ReceipeItemMaker maker = activeMakers.get(player);
        if (maker == null) {
        	RecipeBookItemList response = new RecipeBookItemList(isDwarvenCraft,player.getMaxMp()); 
		 	if (isDwarvenCraft) 
		 		response.addRecipes(player.getDwarvenRecipeBook()); 
		 	else 
		 		response.addRecipes(player.getCommonRecipeBook());
        	player.sendPacket(response);
        	return;
        }
        if (maker.timeReady <= GameTimeController.getGameTicks()) {
        	maker.run();
        	return;
        }
        SystemMessage sm = new SystemMessage(SystemMessage.CANT_ALTER_RECIPEBOOK_WHILE_CRAFTING);
        player.sendPacket(sm);
        return;
	}
	
	public synchronized void requestManufactureItem(L2PcInstance manufacturer, int recipeListId, L2PcInstance player)
	{
		L2RecipeList recipeList = getRecipeList(recipeListId-1);
		
		SystemMessage sm = new SystemMessage(614);
		
		manufacturer.isInCraftMode(true);
		if ((recipeList == null) || (recipeList.getRecipes().length == 0) || (!manufacturer.hasRecipeList(recipeListId)))
		{
			sm = new SystemMessage(614); 
			sm.addString("No recipe for: " + recipeListId);
			player.sendPacket(sm);
        		manufacturer.isInCraftMode(false);
			return;
		}
		if (!Config.ALT_GAME_CREATION) {
			new ReceipeItemMaker(manufacturer, recipeList, player);
		} else {
			ReceipeItemMaker maker = activeMakers.get(manufacturer);
			if (maker != null)
			{
				sm = new SystemMessage(614); 
				sm.addString("Manufacturer are busy creating.");
				sm.addItemName(recipeList.getItemId());
				player.sendPacket(sm);
            			manufacturer.isInCraftMode(false);
				return;
			}
			maker = new ReceipeItemMaker(manufacturer, recipeList, player);
			if (maker.isValid)
				activeMakers.put(manufacturer, maker);
		}
	}
	public synchronized void requestMakeItem(L2PcInstance player, int recipeListId)
	{
		L2RecipeList recipeList = getRecipeList(recipeListId-1);
		
		SystemMessage sm = new SystemMessage(614);
        
    		player.isInCraftMode(true);
		if ((recipeList == null) || (recipeList.getRecipes().length == 0))
		{
			sm = new SystemMessage(614); 
			sm.addString("No recipe for: " + recipeListId);
			player.sendPacket(sm);
            player.isInCraftMode(false);
			return;
		}
		if (!Config.ALT_GAME_CREATION) {
			new ReceipeItemMaker(player, recipeList, player);
		} else {
			ReceipeItemMaker maker = activeMakers.get(player);
			if (maker != null)
			{
				sm = new SystemMessage(614); 
				sm.addString("You are busy creating ");
				sm.addItemName(recipeList.getItemId());
				player.sendPacket(sm);
                player.isInCraftMode(false);
				return;
			}
			maker = new ReceipeItemMaker(player, recipeList, player);
			if (maker.isValid)
				activeMakers.put(player, maker);
		}
	}
	
	public synchronized void requestMakeItemAbort(L2PcInstance player)
	{
		activeMakers.remove(player);
	}
	
	private void parseList(String line)
	{
		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 
	 	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); 
	 		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())
		{
			StringTokenizer st3 = new StringTokenizer(st2.nextToken(), "()");
			int rpItemId = Integer.parseInt(st3.nextToken());
			int quantity = Integer.parseInt(st3.nextToken());
			L2RecipeInstance rp = new L2RecipeInstance(rpItemId, quantity);
			recipePartList.add(rp);
			//recipe.addRecipe(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);
		for (L2RecipeInstance recipePart : recipePartList)
		{
			recipeList.addRecipe(recipePart);
		}
		_lists.put(new Integer(_lists.size()), recipeList);
	}
	
	
	
	
	class ReceipeItemMaker implements Runnable
	{
		int   timeReady;
		final L2PcInstance player;
		final L2PcInstance target;
		final L2RecipeList recipeList;
		final List<L2ItemInstance> items;
		int   materialsRefPrice;
		int   totalItems;
		int   usedItems;
		int   price;
		boolean isValid;
		
		ReceipeItemMaker(L2PcInstance player, L2RecipeList recipeList, L2PcInstance target )
		{
			this.player = player;
			this.target = target;
			this.recipeList = recipeList;
			this.items = new FastList<L2ItemInstance>();
			
			int skillLevel; 
			if (recipeList.isDwarvenRecipe()) 
			{
				skillLevel = player.getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN); 
				if (skillLevel <= 0) 
				{
					player.sendPacket(new ActionFailed()); 
					player.isInCraftMode(false); 
					return;
				} 
			} 
			else 
			{ 
				skillLevel = player.getSkillLevel(L2Skill.SKILL_CREATE_COMMON); 
				if (skillLevel <= 0) 
				{ 
					player.sendPacket(new ActionFailed()); 
					player.isInCraftMode(false); 
					return; 
				} 
			}
			
			if ((recipeList == null) || (recipeList.getRecipes().length == 0))
			{
				SystemMessage sm = new SystemMessage(614); 
				sm.addString("No such recipe");
				player.sendPacket(sm);
                player.isInCraftMode(false);
				return;
			}
			
			if (target != player)
			{
			    for (L2ManufactureItem temp : player.getCreateList().getList())
					if (temp.getRecipeId() == recipeList.getId())
					{
					    price = temp.getCost();
					    if (target.getAdena() < price)
					    {
							target.sendPacket(new SystemMessage(SystemMessage.YOU_NOT_ENOUGH_ADENA));
							player.isInCraftMode(false);
							return;
					    }
					    break;
					}
			}
			if (recipeList.getLevel()>skillLevel)
			{
				SystemMessage sm = new SystemMessage(614); 
				sm.addString("Need skill level "+recipeList.getLevel());
				player.sendPacket(sm);
                player.isInCraftMode(false);
				return;
			}
			/*
			 if (recipeList.getAdenaCost()>activeChar.getAdena())
			 {
			 SystemMessage sm = new SystemMessage(614); 
			 sm.addString("Need "+recipeList.getAdenaCost()+" Adena");
			 activeChar.sendPacket(sm);
			 return;
			 }*/
			
			L2RecipeInstance[] recipes = recipeList.getRecipes();
			
			Inventory inv = target.getInventory();
			
			for (L2RecipeInstance recipe : recipes)
			{
				if (recipe.getQuantity() != 0)
				{
					L2ItemInstance invItem = inv.getItemByItemId(recipe.getItemId());
					if ((invItem == null) || ((recipeList.isConsumable() ? (int)(recipe.getQuantity() * Config.RATE_CONSUMABLE_COST) : recipe.getQuantity()) > invItem.getCount()))
					{
						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);
						return;
					}
				}
			}
			
			if (!Config.ALT_GAME_CREATION)
			{
				if (player.getCurrentMp() < recipeList.getMpCost())
				{
					if (Config.DEBUG) _log.fine("not enough mana");
					target.sendPacket(new SystemMessage(SystemMessage.NOT_ENOUGH_MP));
					timeReady = GameTimeController.getGameTicks();
                    player.isInCraftMode(false);
					return;
				}
			}
			
			for (L2RecipeInstance recipe : recipes)
			{
				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();
				}
			}
			
			isValid = true; 
			
			timeReady = GameTimeController.TICKS_PER_SECOND + GameTimeController.getGameTicks();
			ClientScheduler.getInstance().scheduleLow(this, 1100);
		}
		
		public void run()
		{
            player.isInCraftMode(true);
            
			if ( Config.IS_CRAFTING_ENABLED ) {
				double currentPlayerMp = player.getCurrentMp(); 
				if (currentPlayerMp < recipeList.getMpCost()) {
					if (Config.DEBUG) _log.fine("not enough mana");
					target.sendPacket(new SystemMessage(SystemMessage.NOT_ENOUGH_MP));
					timeReady = GameTimeController.getGameTicks();
                    player.isInCraftMode(false);
					return;
				}
				
				int gameTicks = GameTimeController.getGameTicks();	
				if (timeReady > gameTicks)
                {
                    player.isInCraftMode(false);
					return;
                }
				
				timeReady = gameTicks + (int)(15 * player.getMReuseRate(player.getKnownSkill(172)) * GameTimeController.TICKS_PER_SECOND);			
				
				if (!Config.ALT_GAME_CREATION || items.isEmpty())
				{
					player.reduceCurrentMp(recipeList.getMpCost());
					
					if(Rnd.get(100) < recipeList.getSuccessRate()) 
					{
						int itemId = recipeList.getItemId();
						int itemCount = recipeList.getCount();
						
						if (target != player)
						{
						    if (price > 0)
						    {
								target.reduceAdena("Manufacture", price, player, false);
								player.addAdena("Manufacture", price, target, false);
						    }

						    StatusUpdate su2 = new StatusUpdate(target.getObjectId());
						    su2.addAttribute(StatusUpdate.CUR_LOAD, target.getCurrentLoad());
						    target.sendPacket(su2);
						}

						L2ItemInstance createdItem = target.getInventory().addItem("Manufacture", itemId, itemCount, target, player);
						SystemMessage sm = new SystemMessage(SystemMessage.EARNED_ITEM);
						sm.addItemName(itemId);
						sm.addNumber(itemCount);
						target.sendPacket(sm);

						if (Config.ALT_GAME_CREATION) {
							int skillLevel;
							if (recipeList.isDwarvenRecipe()) 
								skillLevel = player.getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN); 
							else 
								skillLevel = player.getSkillLevel(L2Skill.SKILL_CREATE_COMMON); 
							int receipeLevel = recipeList.getLevel();
							int exp = createdItem.getReferencePrice()*itemCount;
							// one variation
							exp -= materialsRefPrice;
							if (exp < 0) exp = 0;
							// another variation
							// exp /= receipeLevel
							for (int i=skillLevel; i > receipeLevel; 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));
						}
					}
					else
					{
						player.sendMessage("Item(s) failed to create");
                        player.isInCraftMode(false);
					}
					activeMakers.remove(player);
                    player.isInCraftMode(false);
					
					StatusUpdate su = new StatusUpdate(player.getObjectId());
				    su.addAttribute(StatusUpdate.CUR_LOAD, player.getCurrentLoad());
					su.addAttribute(StatusUpdate.CUR_MP, (int) player.getCurrentMp());
					player.sendPacket(su);

					target.sendPacket(new ItemList(target, false));
				    if (target == player) target.sendPacket(new RecipeItemMakeInfo(recipeList.getId(),target));
					else target.sendPacket(new RecipeShopItemInfo(player.getObjectId(),recipeList.getId()));
				} 
				else {
					double currentMp = player.getCurrentMp(); 
					if (currentMp < recipeList.getMpCost()) {
						if (Config.DEBUG) _log.fine("not enough mana");
						SystemMessage sm = new SystemMessage(SystemMessage.NOT_ENOUGH_MP); 
						if (target == null)
						    player.sendPacket(sm);
						else
						    target.sendPacket(sm);
						timeReady = GameTimeController.getGameTicks();
                        player.isInCraftMode(false);
						return;
					}
					player.setCurrentMp(currentMp - recipeList.getMpCost());
					
					int numItems = player.getSkillLevel(172);
					while (numItems > 0 && !items.isEmpty()) {
						L2ItemInstance item = items.get(0);
						
						int count = item.getCount();
						if (count >= numItems) count = numItems;
						
						item.setCount(item.getCount() - count);
						if (item.getCount() <= 0) items.remove(0);
						
						numItems -= count;
						usedItems += count;
						
						SystemMessage sm = new SystemMessage(368);
						sm.addNumber(count);
						sm.addItemName(item.getItemId());
						if (target == null)
						    player.sendPacket(sm);
						else
						    target.sendPacket(sm);
						
                        player.isInCraftMode(false);
					}
					
					int delay = (timeReady-gameTicks) * GameTimeController.MILLIS_IN_TICK;
					MagicSkillUser msk = new MagicSkillUser(player, 1050, 1, delay, 0);
					player.broadcastPacket(msk);
					SetupGauge sg = new SetupGauge(0, delay);
					player.sendPacket(sg);				
					
					ClientScheduler.getInstance().scheduleLow(this, 100+delay);
				}
			}
			else {
				// crafting is disabled...
				SystemMessage sm = new SystemMessage(614);
				sm.addString("Crafting is currently disabled.");
				if (target == null)
				    player.sendPacket(sm);
				else
				    target.sendPacket(sm);
                player.isInCraftMode(false);
			}
		}
	}
}