rendered paste bodyIndex: C:/workspace/c4/java/net/sf/l2j/gameserver/RecipeController.java
===================================================================
--- C:/workspace/c4/java/net/sf/l2j/gameserver/RecipeController.java (revision 1680)
+++ C:/workspace/c4/java/net/sf/l2j/gameserver/RecipeController.java (working copy)
@@ -35,6 +35,7 @@
import net.sf.l2j.Config;
import net.sf.l2j.gameserver.ClientScheduler;
import net.sf.l2j.gameserver.GameTimeController;
+import net.sf.l2j.gameserver.idfactory.IdFactory;
import net.sf.l2j.gameserver.lib.Rnd;
import net.sf.l2j.gameserver.model.Inventory;
import net.sf.l2j.gameserver.model.L2ItemInstance;
@@ -42,6 +43,7 @@
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.L2World;
import net.sf.l2j.gameserver.model.actor.instance.L2PcInstance;
import net.sf.l2j.gameserver.serverpackets.ActionFailed;
import net.sf.l2j.gameserver.serverpackets.ItemList;
@@ -159,7 +161,8 @@
public synchronized void requestMakeItemAbort(L2PcInstance player)
{
- activeMakers.remove(player);
+ if(activeMakers!=null) activeMakers.remove(player);
+ player.isInCraftMode(false);
}
public synchronized void requestManufactureItem(L2PcInstance manufacturer, int recipeListId,
@@ -170,21 +173,23 @@
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.");
+ manufacturer.isInCraftMode(false);
+ 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;
- }
- maker = new RecipeItemMaker(manufacturer, recipeList, player);
- if (maker.isValid) activeMakers.put(manufacturer, maker);
+ activeMakers.put(manufacturer, maker);
+ ClientScheduler.scheduleEvent(maker, 100);
+ } else maker.run();
}
}
@@ -192,28 +197,34 @@
{
L2RecipeList recipeList = getValidRecipeList(player, recipeListId);
- if (recipeList == null) return;
-
+ if (recipeList == null)
+ {
+ _log.warning("recipelist == null");
+ return;
+ }
+
player.isInCraftMode(true);
- if (!Config.ALT_GAME_CREATION)
+ RecipeItemMaker maker;
+
+ if (Config.ALT_GAME_CREATION && ((maker = activeMakers.get(player)) != null)) // already have something cooking (possible in alt mode only)
{
- new RecipeItemMaker(player, recipeList, player);
+ SystemMessage sm = new SystemMessage(614);
+ sm.addString("You are busy creating ");
+ sm.addItemName(recipeList.getItemId());
+ player.sendPacket(sm);
+ player.isInCraftMode(false);
+ return;
}
- else
+
+ maker = new RecipeItemMaker(player, recipeList, player);
+ if(maker.isValid)
{
- RecipeItemMaker maker = activeMakers.get(player);
- if (maker != null)
+ 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;
- }
- maker = new RecipeItemMaker(player, recipeList, player);
- if (maker.isValid) activeMakers.put(player, maker);
+ activeMakers.put(player, maker);
+ ClientScheduler.scheduleEvent(maker, 100);
+ } else maker.run();
}
}
@@ -234,7 +245,7 @@
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;
}
@@ -281,118 +292,174 @@
public class RecipeItemMaker implements Runnable
{
public boolean isValid;
- final List<L2ItemInstance> items;
- int materialsRefPrice;
- final L2PcInstance player;
+ List<L2ItemInstance> items = null;
+ final L2RecipeList recipeList;
+ final L2PcInstance player; // "crafter"
+ final L2PcInstance target; // "customer"
+ final L2Skill skill;
+ final int skillId;
+ final int skillLevel;
+ int 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;
+ this.skillId = recipeList.isDwarvenRecipe() ? L2Skill.SKILL_CREATE_DWARVEN
+ : L2Skill.SKILL_CREATE_COMMON;
+ this.skillLevel = player.getSkillLevel(skillId);
+ this.skill = player.getKnownSkill(skillId);
- skillLevel = recipeList.isDwarvenRecipe() ? player.getSkillLevel(L2Skill.SKILL_CREATE_DWARVEN)
- : player.getSkillLevel(L2Skill.SKILL_CREATE_COMMON);
+ // validate recipe list
+ if ((recipeList == null) || (recipeList.getRecipes().length == 0))
+ {
+ player.sendMessage("No such recipe");
+ player.sendPacket(new ActionFailed());
+ abort(false);
+ return;
+ }
- if (!validateSkillLevel()) return;
- if (!validateRecipeList()) return;
- if (!validateCustomerCanAfford(target,player)) return;
- if (!validateMaterials()) return;
- if (!validateMp()) return;
+ this.manaRequired = this.recipeList.getMpCost();
+
+ // validate skill level
+ if (this.recipeList.getLevel() > skillLevel)
+ {
+ player.sendMessage("Need skill level " + this.recipeList.getLevel());
+ player.sendPacket(new ActionFailed());
+ abort(false);
+ return;
+ }
- isValid = true;
- updateTime();
- run();
- }
-
- private void finishCrafting()
- {
- player.reduceCurrentMp(recipeList.getMpCost());
-
- if (Rnd.get(100) < recipeList.getSuccessRate())
+ // check that customer can afford to pay for creation services
+ if (player != target)
{
- if (target != player)
- {
- if (price > 0)
+ for (L2ManufactureItem temp : player.getCreateList().getList())
+ if (temp.getRecipeId() == this.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(false);
+ return;
+ }
+ break;
}
- updateCurLoad();
- }
-
- RewardPlayer();
- updateMakeInfo(true); // success
}
- else
+
+ // make temporary items
+ if ((items = getItems(false)) == null) return;
+
+ // calculate reference price
+ for (L2ItemInstance i : items)
{
- player.sendMessage("Item(s) failed to create");
- updateMakeInfo(false);
+ materialsRefPrice += i.getReferencePrice() * i.getCount();
+ totalItems += i.getCount();
}
- activeMakers.remove(player);
- player.isInCraftMode(false);
+
+ if(player.getCurrentMp()<manaRequired)
+ {
+ target.sendPacket(new SystemMessage(SystemMessage.NOT_ENOUGH_MP));
+ abort(false);
+ return;
+ }
- target.sendPacket(new ItemList(target, false));
+ // 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) // update mana required to "per pass"
+ manaRequired /= (double)creationPasses; // checks to validateMp() will only need portion of mp for one pass
+
+ this.isValid = true;
}
public void run()
{
player.isInCraftMode(true);
- gameTicks = GameTimeController.getGameTicks();
- if (!validateCraftingEnabled() || !validateMp()) return;
- updateTime();
+ if (!Config.IS_CRAFTING_ENABLED)
+ {
+ target.sendMessage("Crafting is currently disabled.");
+ abort(false);
+ return;
+ }
+
+ if(Config.ALT_GAME_CREATION && activeMakers.get(player)==null)
+ {
+ player.sendMessage("Crafting aborted");
+ abort(true);
+ };
+ // check mana
+ if (!validateMp()) return;
+
+ // divided by RATE_CONSUMABLES_COST to remove craft time increase on higher consumable rates (more mats consumed -> more time)
+ 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: this is not working ... this should be animation of crafting skill ?? or what ?
+ MagicSkillUser msk = new MagicSkillUser(player, skillId, skillLevel, delay, 0);
player.broadcastPacket(msk);
player.sendPacket(new SetupGauge(0, delay));
- ClientScheduler.getInstance().scheduleLow(this, 100 + delay);
+ ClientScheduler.scheduleEvent(this, 100 + delay);
}
- else finishCrafting();
+ else // finish crafting
+ {
+ player.reduceCurrentMp(manaRequired);
+ if (Rnd.get(100) < recipeList.getSuccessRate())
+ {
+ if (target != player) // customer must pay for services
+ {
+ if (price > 0)
+ {
+ target.transferItem("PayForCrafting",
+ target.getInventory().getAdenaInstance().getObjectId(),
+ price, player.getInventory(), null);
+ }
+ updateCurLoad();
+ }
+
+ if ((items = getItems(true)) != null) // this line actually takes materials from inventory
+ RewardPlayer(); // and this one immediately puts created item in its place
+ else updateMakeInfo(false);
+ }
+ else
+ {
+ player.sendMessage("Item(s) failed to create");
+ updateMakeInfo(false);
+ }
+ if (Config.ALT_GAME_CREATION) activeMakers.remove(player);
+ player.isInCraftMode(false);
+ target.sendPacket(new ItemList(target, false));
+ }
+
// 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()));
}
@@ -413,7 +480,7 @@
private void grabSomeItems()
{
- int numItems = player.getSkillLevel(172);
+ int numItems = skillLevel;
while (numItems > 0 && !items.isEmpty())
{
L2ItemInstance item = items.get(0);
@@ -423,135 +490,99 @@
item.setCount(item.getCount() - count);
if (item.getCount() <= 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);
+ // FIXME: should not send "you equipped ... " message to customer so I improvised
+ if (target == player) player.sendPacket(sm);
+ else target.sendMessage("Manufacturer " + player.getName() + " used " + count + " "
+ + item.getItem().getName());
}
}
- 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);
+ abort(true); // true == can resume
}
- 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); // false == don't resume
+ }
return false;
}
return true;
}
- private boolean validateMaterials()
+ private List<L2ItemInstance> getItems(boolean remove)
{
L2RecipeInstance[] recipes = recipeList.getRecipes();
-
Inventory inv = target.getInventory();
+ List<L2ItemInstance> materials = new FastList<L2ItemInstance>();
for (L2RecipeInstance recipe : recipes)
{
- if (recipe.getQuantity() != 0)
+ int quantity = (int) recipe.getQuantity();
+ if (recipeList.isConsumable())
+ quantity = (int) (quantity * Config.RATE_CONSUMABLE_COST);
+
+ 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());
+ int old_quantity = item.getCount(); // remember old quantity
+
+ // now we verify that we have enough materials
+ if (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;
+ abort(false);
+ return null;
}
- }
- }
- 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();
+ // make new temporary object, just for counting puroses, real item modification only
+ // on finishCrafting() so we minimize risk of losing items
+
+ L2ItemInstance temp = new L2ItemInstance(IdFactory.getInstance().getNextId(),
+ item.getItem().getItemId());
+ temp.setCount("TemporaryCraftObject", quantity, target, player);
+ materials.add(temp);
+
+ if (remove) item.setCount("Manufacture", old_quantity - quantity, target, player);
}
}
-
- return true;
+ return materials;
}
- private boolean validateSkillLevel()
+ private void abort(boolean resume)
{
- if (recipeList.getLevel() > skillLevel)
+
+ if (resume)
{
- player.sendMessage("Need skill level " + recipeList.getLevel());
- player.sendPacket(new ActionFailed());
- player.isInCraftMode(false);
- activeMakers.remove(player);
- updateMakeInfo(false);
- return false;
+ // will continue later, run() is scheduled to run in 100+delay miliseconds so no worry
+ // about blocking other things ... requestMakeItemAbort will interrupt this properly ?
}
- return true;
- }
-
- private boolean validateRecipeList()
- {
- if ((recipeList == null) || (recipeList.getRecipes().length == 0))
+ else
{
- player.sendMessage("No such recipe");
+ updateMakeInfo(false);
+ activeMakers.remove(player);
player.isInCraftMode(false);
- activeMakers.remove(player);
- updateMakeInfo(false);
- return false;
}
- return true;
}
private void RewardPlayer()
@@ -561,35 +592,48 @@
L2ItemInstance createdItem = target.getInventory().addItem("Manufacture", itemId, itemCount,
target, player);
+
+ // inform customer of earned item
SystemMessage sm = new SystemMessage(SystemMessage.EARNED_ITEM);
sm.addItemName(itemId);
sm.addNumber(itemCount);
target.sendPacket(sm);
+ // 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;
-
+
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 gained ...
+ // so 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) my goal is to make ALT_GAME_CREATION
+ // a *bit* slower, a bit more interesting, and give some xp/sp but not too much
+ // comments on this would be welcome.
+
+ player.addExpAndSp((int) player.calcStat(Stats.EXPSP_RATE, exp * Config.RATE_XP
+ * Config.ALT_GAME_CREATION_XP_RATE * Config.ALT_GAME_CREATION_SPEED, null, null),
+ (int) player.calcStat(Stats.EXPSP_RATE, sp * Config.RATE_SP
+ * Config.ALT_GAME_CREATION_SP_RATE
+ * Config.ALT_GAME_CREATION_SPEED, null, null));
}
+ updateMakeInfo(true); // success
}
}
@@ -605,7 +649,5 @@
}
return recipeList;
};
-
}
-