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);
}
}
}
}