Multisell enchanted items support.

This commit is contained in:
MobiusDev 2018-03-29 14:43:23 +00:00
parent 6382642e1a
commit 1db5262d58
36 changed files with 660 additions and 150 deletions

View File

@ -88,7 +88,7 @@ public final class MultisellData implements IGameXmlReader
{
if ("item".equalsIgnoreCase(itemNode.getNodeName()))
{
final List<ItemHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> products = new ArrayList<>(1);
final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
@ -98,7 +98,8 @@ public final class MultisellData implements IGameXmlReader
{
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final ItemHolder ingredient = new ItemHolder(id, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel);
if (itemExists(ingredient))
{
@ -115,7 +116,8 @@ public final class MultisellData implements IGameXmlReader
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
if (itemExists(product))
{

View File

@ -28,6 +28,7 @@ import com.l2jmobius.commons.util.Rnd;
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
private final byte _enchantmentLevel;
public ItemChanceHolder(int id, double chance)
{
@ -38,6 +39,14 @@ public class ItemChanceHolder extends ItemHolder
{
super(id, count);
_chance = chance;
_enchantmentLevel = 0;
}
public ItemChanceHolder(int id, double chance, long count, byte enchantmentLevel)
{
super(id, count);
_chance = chance;
_enchantmentLevel = enchantmentLevel;
}
/**
@ -49,6 +58,15 @@ public class ItemChanceHolder extends ItemHolder
return _chance;
}
/**
* Gets the enchant level.
* @return the enchant level of the item contained in this object
*/
public byte getEnchantmentLevel()
{
return _enchantmentLevel;
}
/**
* Calculates a cumulative chance of all given holders. If all holders' chance sum up to 100% or above, there is 100% guarantee a holder will be selected.
* @param holders list of holders to calculate chance from.

View File

@ -29,17 +29,17 @@ import com.l2jmobius.gameserver.model.items.L2Item;
public class MultisellEntryHolder
{
private final boolean _stackable;
private final List<ItemHolder> _ingredients;
private final List<ItemChanceHolder> _ingredients;
private final List<ItemChanceHolder> _products;
public MultisellEntryHolder(List<ItemHolder> ingredients, List<ItemChanceHolder> products)
public MultisellEntryHolder(List<ItemChanceHolder> ingredients, List<ItemChanceHolder> products)
{
_ingredients = Collections.unmodifiableList(ingredients);
_products = Collections.unmodifiableList(products);
_stackable = products.stream().map(i -> ItemTable.getInstance().getTemplate(i.getId())).filter(Objects::nonNull).allMatch(L2Item::isStackable);
}
public final List<ItemHolder> getIngredients()
public final List<ItemChanceHolder> getIngredients()
{
return _ingredients;
}

View File

@ -435,6 +435,21 @@ public class PcInventory extends Inventory
*/
@Override
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
return addItem(process, itemId, count, actor, reference, true);
}
/**
* Adds item in inventory and checks _adena and _ancientAdena
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be added
* @param count : int Quantity of items to be added
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @param update : Update inventory (not used by MultiSellChoose packet / it sends update after finish)
* @return L2ItemInstance corresponding to the new item or the updated item in inventory
*/
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference, boolean update)
{
final L2ItemInstance item = super.addItem(process, itemId, count, actor, reference);
if (item != null)
@ -456,15 +471,18 @@ public class PcInventory extends Inventory
if ((item != null) && (actor != null))
{
// Send inventory update packet
if (!Config.FORCE_INVENTORY_UPDATE)
if (update)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
if (!Config.FORCE_INVENTORY_UPDATE)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
}
}
// Notify to scripts

View File

@ -33,7 +33,6 @@ import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
@ -243,6 +242,33 @@ public class MultiSellChoose implements IClientIncomingPacket
// Summarize all item counts into one map. That would include non-stackable items under 1 id and multiple count.
final Map<Integer, Long> itemIdCount = entry.getIngredients().stream().collect(Collectors.toMap(i -> i.getId(), i -> list.getIngredientCount(i), (k1, k2) -> Math.addExact(k1, k2)));
// Check for enchanted level requirements.
for (ItemChanceHolder ingredient : entry.getIngredients())
{
if (ingredient.getEnchantmentLevel() == 0)
{
continue;
}
int found = 0;
for (L2ItemInstance item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
{
if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
{
found++;
}
}
if (found < ingredient.getCount())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemTable.getInstance().getTemplate(ingredient.getId()).getName());
player.sendPacket(sm);
return;
}
itemIdCount.remove(ingredient.getId()); // Since we check now.
}
// Now check if the player has sufficient items in the inventory to cover the ingredients' expences. Take care for non-stackable items like 2 swords to dual.
boolean allOk = true;
for (Entry<Integer, Long> idCount : itemIdCount.entrySet())
@ -260,7 +286,7 @@ public class MultiSellChoose implements IClientIncomingPacket
boolean itemEnchantmentProcessed = (itemEnchantment == null);
// Take all ingredients
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
@ -306,6 +332,23 @@ public class MultiSellChoose implements IClientIncomingPacket
}
}
}
else if (ingredient.getEnchantmentLevel() > 0)
{
// Take the enchanted item.
final L2ItemInstance destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
if (destroyedItem != null)
{
itemEnchantmentProcessed = true;
iu.addItem(destroyedItem);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addItemName(ingredient.getId());
player.sendPacket(sm);
return;
}
}
else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
{
// Take the enchanted item.
@ -390,8 +433,7 @@ public class MultiSellChoose implements IClientIncomingPacket
else
{
// Give item.
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc);
iu.addItem(addedItem);
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
// Check if the newly given item should be enchanted.
if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getItem().getClass().equals(itemEnchantment.getItem().getClass()))
@ -405,12 +447,15 @@ public class MultiSellChoose implements IClientIncomingPacket
addedItem.setAttribute(new AttributeHolder(AttributeType.EARTH, itemEnchantment.getAttributeDefence(AttributeType.EARTH)), false);
addedItem.setAttribute(new AttributeHolder(AttributeType.HOLY, itemEnchantment.getAttributeDefence(AttributeType.HOLY)), false);
addedItem.setAttribute(new AttributeHolder(AttributeType.DARK, itemEnchantment.getAttributeDefence(AttributeType.DARK)), false);
addedItem.updateDatabase();
// Mark that we have already upgraded the item.
itemEnchantmentProcessed = false;
}
if (product.getEnchantmentLevel() > 0)
{
addedItem.setEnchantLevel(product.getEnchantmentLevel());
addedItem.updateDatabase();
}
if (addedItem.getCount() > 1)
{
@ -432,6 +477,9 @@ public class MultiSellChoose implements IClientIncomingPacket
sm.addItemName(addedItem);
player.sendPacket(sm);
}
// Inventory update.
iu.addItem(addedItem);
}
}
@ -470,7 +518,7 @@ public class MultiSellChoose implements IClientIncomingPacket
* @param totalCount
* @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
*/
private boolean checkIngredients(final L2PcInstance player, PreparedMultisellListHolder list, final PcInventory inventory, final L2Clan clan, final int ingredientId, final long totalCount)
private boolean checkIngredients(L2PcInstance player, PreparedMultisellListHolder list, PcInventory inventory, L2Clan clan, int ingredientId, long totalCount)
{
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
if (specialItem != null)

View File

@ -22,7 +22,6 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.ItemInfo;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
@ -96,13 +95,13 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeH(65535);
}
packet.writeQ(_list.getProductCount(product));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(product.getEnchantmentLevel() > 0 ? product.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeD((int) Math.ceil(product.getChance())); // chance
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
}
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final L2Item template = ItemTable.getInstance().getTemplate(ingredient.getId());
final ItemInfo displayItemEnchantment = ((itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId())) ? itemEnchantment : null;
@ -110,7 +109,7 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeD(ingredient.getId());
packet.writeH(template != null ? template.getType2() : 65535);
packet.writeQ(_list.getIngredientCount(ingredient));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(ingredient.getEnchantmentLevel() > 0 ? ingredient.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
}

View File

@ -88,7 +88,7 @@ public final class MultisellData implements IGameXmlReader
{
if ("item".equalsIgnoreCase(itemNode.getNodeName()))
{
final List<ItemHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> products = new ArrayList<>(1);
final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
@ -98,7 +98,8 @@ public final class MultisellData implements IGameXmlReader
{
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final ItemHolder ingredient = new ItemHolder(id, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel);
if (itemExists(ingredient))
{
@ -115,7 +116,8 @@ public final class MultisellData implements IGameXmlReader
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
if (itemExists(product))
{

View File

@ -28,6 +28,7 @@ import com.l2jmobius.commons.util.Rnd;
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
private final byte _enchantmentLevel;
public ItemChanceHolder(int id, double chance)
{
@ -38,6 +39,14 @@ public class ItemChanceHolder extends ItemHolder
{
super(id, count);
_chance = chance;
_enchantmentLevel = 0;
}
public ItemChanceHolder(int id, double chance, long count, byte enchantmentLevel)
{
super(id, count);
_chance = chance;
_enchantmentLevel = enchantmentLevel;
}
/**
@ -49,6 +58,15 @@ public class ItemChanceHolder extends ItemHolder
return _chance;
}
/**
* Gets the enchant level.
* @return the enchant level of the item contained in this object
*/
public byte getEnchantmentLevel()
{
return _enchantmentLevel;
}
/**
* Calculates a cumulative chance of all given holders. If all holders' chance sum up to 100% or above, there is 100% guarantee a holder will be selected.
* @param holders list of holders to calculate chance from.

View File

@ -29,17 +29,17 @@ import com.l2jmobius.gameserver.model.items.L2Item;
public class MultisellEntryHolder
{
private final boolean _stackable;
private final List<ItemHolder> _ingredients;
private final List<ItemChanceHolder> _ingredients;
private final List<ItemChanceHolder> _products;
public MultisellEntryHolder(List<ItemHolder> ingredients, List<ItemChanceHolder> products)
public MultisellEntryHolder(List<ItemChanceHolder> ingredients, List<ItemChanceHolder> products)
{
_ingredients = Collections.unmodifiableList(ingredients);
_products = Collections.unmodifiableList(products);
_stackable = products.stream().map(i -> ItemTable.getInstance().getTemplate(i.getId())).filter(Objects::nonNull).allMatch(L2Item::isStackable);
}
public final List<ItemHolder> getIngredients()
public final List<ItemChanceHolder> getIngredients()
{
return _ingredients;
}

View File

@ -435,6 +435,21 @@ public class PcInventory extends Inventory
*/
@Override
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
return addItem(process, itemId, count, actor, reference, true);
}
/**
* Adds item in inventory and checks _adena and _ancientAdena
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be added
* @param count : int Quantity of items to be added
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @param update : Update inventory (not used by MultiSellChoose packet / it sends update after finish)
* @return L2ItemInstance corresponding to the new item or the updated item in inventory
*/
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference, boolean update)
{
final L2ItemInstance item = super.addItem(process, itemId, count, actor, reference);
if (item != null)
@ -456,15 +471,18 @@ public class PcInventory extends Inventory
if ((item != null) && (actor != null))
{
// Send inventory update packet
if (!Config.FORCE_INVENTORY_UPDATE)
if (update)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
if (!Config.FORCE_INVENTORY_UPDATE)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
}
}
// Notify to scripts

View File

@ -36,7 +36,6 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.ensoul.EnsoulOption;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
@ -271,6 +270,33 @@ public class MultiSellChoose implements IClientIncomingPacket
// Summarize all item counts into one map. That would include non-stackable items under 1 id and multiple count.
final Map<Integer, Long> itemIdCount = entry.getIngredients().stream().collect(Collectors.toMap(i -> i.getId(), i -> list.getIngredientCount(i), (k1, k2) -> Math.addExact(k1, k2)));
// Check for enchanted level requirements.
for (ItemChanceHolder ingredient : entry.getIngredients())
{
if (ingredient.getEnchantmentLevel() == 0)
{
continue;
}
int found = 0;
for (L2ItemInstance item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
{
if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
{
found++;
}
}
if (found < ingredient.getCount())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemTable.getInstance().getTemplate(ingredient.getId()).getName());
player.sendPacket(sm);
return;
}
itemIdCount.remove(ingredient.getId()); // Since we check now.
}
// Now check if the player has sufficient items in the inventory to cover the ingredients' expences. Take care for non-stackable items like 2 swords to dual.
boolean allOk = true;
for (Entry<Integer, Long> idCount : itemIdCount.entrySet())
@ -288,7 +314,7 @@ public class MultiSellChoose implements IClientIncomingPacket
boolean itemEnchantmentProcessed = (itemEnchantment == null);
// Take all ingredients
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
@ -334,6 +360,23 @@ public class MultiSellChoose implements IClientIncomingPacket
}
}
}
else if (ingredient.getEnchantmentLevel() > 0)
{
// Take the enchanted item.
final L2ItemInstance destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
if (destroyedItem != null)
{
itemEnchantmentProcessed = true;
iu.addItem(destroyedItem);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addItemName(ingredient.getId());
player.sendPacket(sm);
return;
}
}
else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
{
// Take the enchanted item.
@ -418,8 +461,7 @@ public class MultiSellChoose implements IClientIncomingPacket
else
{
// Give item.
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc);
iu.addItem(addedItem);
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
// Check if the newly given item should be enchanted.
if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getItem().getClass().equals(itemEnchantment.getItem().getClass()))
@ -447,12 +489,15 @@ public class MultiSellChoose implements IClientIncomingPacket
addedItem.addSpecialAbility(_soulCrystalSpecialOptions[i], i + 1, 2, false);
}
}
addedItem.updateDatabase();
// Mark that we have already upgraded the item.
itemEnchantmentProcessed = false;
}
if (product.getEnchantmentLevel() > 0)
{
addedItem.setEnchantLevel(product.getEnchantmentLevel());
addedItem.updateDatabase();
}
if (addedItem.getCount() > 1)
{
@ -474,6 +519,9 @@ public class MultiSellChoose implements IClientIncomingPacket
sm.addItemName(addedItem);
player.sendPacket(sm);
}
// Inventory update.
iu.addItem(addedItem);
}
}
@ -512,7 +560,7 @@ public class MultiSellChoose implements IClientIncomingPacket
* @param totalCount
* @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
*/
private boolean checkIngredients(final L2PcInstance player, PreparedMultisellListHolder list, final PcInventory inventory, final L2Clan clan, final int ingredientId, final long totalCount)
private boolean checkIngredients(L2PcInstance player, PreparedMultisellListHolder list, PcInventory inventory, L2Clan clan, int ingredientId, long totalCount)
{
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
if (specialItem != null)

View File

@ -22,7 +22,6 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.ItemInfo;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
@ -97,14 +96,14 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeH(65535);
}
packet.writeQ(_list.getProductCount(product));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(product.getEnchantmentLevel() > 0 ? product.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeD((int) Math.ceil(product.getChance())); // chance
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);
}
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final L2Item template = ItemTable.getInstance().getTemplate(ingredient.getId());
final ItemInfo displayItemEnchantment = ((itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId())) ? itemEnchantment : null;
@ -112,7 +111,7 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeD(ingredient.getId());
packet.writeH(template != null ? template.getType2() : 65535);
packet.writeQ(_list.getIngredientCount(ingredient));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(ingredient.getEnchantmentLevel() > 0 ? ingredient.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);

View File

@ -88,7 +88,7 @@ public final class MultisellData implements IGameXmlReader
{
if ("item".equalsIgnoreCase(itemNode.getNodeName()))
{
final List<ItemHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> products = new ArrayList<>(1);
final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
@ -98,7 +98,8 @@ public final class MultisellData implements IGameXmlReader
{
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final ItemHolder ingredient = new ItemHolder(id, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel);
if (itemExists(ingredient))
{
@ -115,7 +116,8 @@ public final class MultisellData implements IGameXmlReader
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
if (itemExists(product))
{

View File

@ -28,6 +28,7 @@ import com.l2jmobius.commons.util.Rnd;
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
private final byte _enchantmentLevel;
public ItemChanceHolder(int id, double chance)
{
@ -38,6 +39,14 @@ public class ItemChanceHolder extends ItemHolder
{
super(id, count);
_chance = chance;
_enchantmentLevel = 0;
}
public ItemChanceHolder(int id, double chance, long count, byte enchantmentLevel)
{
super(id, count);
_chance = chance;
_enchantmentLevel = enchantmentLevel;
}
/**
@ -49,6 +58,15 @@ public class ItemChanceHolder extends ItemHolder
return _chance;
}
/**
* Gets the enchant level.
* @return the enchant level of the item contained in this object
*/
public byte getEnchantmentLevel()
{
return _enchantmentLevel;
}
/**
* Calculates a cumulative chance of all given holders. If all holders' chance sum up to 100% or above, there is 100% guarantee a holder will be selected.
* @param holders list of holders to calculate chance from.

View File

@ -29,17 +29,17 @@ import com.l2jmobius.gameserver.model.items.L2Item;
public class MultisellEntryHolder
{
private final boolean _stackable;
private final List<ItemHolder> _ingredients;
private final List<ItemChanceHolder> _ingredients;
private final List<ItemChanceHolder> _products;
public MultisellEntryHolder(List<ItemHolder> ingredients, List<ItemChanceHolder> products)
public MultisellEntryHolder(List<ItemChanceHolder> ingredients, List<ItemChanceHolder> products)
{
_ingredients = Collections.unmodifiableList(ingredients);
_products = Collections.unmodifiableList(products);
_stackable = products.stream().map(i -> ItemTable.getInstance().getTemplate(i.getId())).filter(Objects::nonNull).allMatch(L2Item::isStackable);
}
public final List<ItemHolder> getIngredients()
public final List<ItemChanceHolder> getIngredients()
{
return _ingredients;
}

View File

@ -435,6 +435,21 @@ public class PcInventory extends Inventory
*/
@Override
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
return addItem(process, itemId, count, actor, reference, true);
}
/**
* Adds item in inventory and checks _adena and _ancientAdena
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be added
* @param count : int Quantity of items to be added
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @param update : Update inventory (not used by MultiSellChoose packet / it sends update after finish)
* @return L2ItemInstance corresponding to the new item or the updated item in inventory
*/
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference, boolean update)
{
final L2ItemInstance item = super.addItem(process, itemId, count, actor, reference);
if (item != null)
@ -456,15 +471,18 @@ public class PcInventory extends Inventory
if ((item != null) && (actor != null))
{
// Send inventory update packet
if (!Config.FORCE_INVENTORY_UPDATE)
if (update)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
if (!Config.FORCE_INVENTORY_UPDATE)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
}
}
// Notify to scripts

View File

@ -36,7 +36,6 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.ensoul.EnsoulOption;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
@ -271,6 +270,33 @@ public class MultiSellChoose implements IClientIncomingPacket
// Summarize all item counts into one map. That would include non-stackable items under 1 id and multiple count.
final Map<Integer, Long> itemIdCount = entry.getIngredients().stream().collect(Collectors.toMap(i -> i.getId(), i -> list.getIngredientCount(i), (k1, k2) -> Math.addExact(k1, k2)));
// Check for enchanted level requirements.
for (ItemChanceHolder ingredient : entry.getIngredients())
{
if (ingredient.getEnchantmentLevel() == 0)
{
continue;
}
int found = 0;
for (L2ItemInstance item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
{
if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
{
found++;
}
}
if (found < ingredient.getCount())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemTable.getInstance().getTemplate(ingredient.getId()).getName());
player.sendPacket(sm);
return;
}
itemIdCount.remove(ingredient.getId()); // Since we check now.
}
// Now check if the player has sufficient items in the inventory to cover the ingredients' expences. Take care for non-stackable items like 2 swords to dual.
boolean allOk = true;
for (Entry<Integer, Long> idCount : itemIdCount.entrySet())
@ -288,7 +314,7 @@ public class MultiSellChoose implements IClientIncomingPacket
boolean itemEnchantmentProcessed = (itemEnchantment == null);
// Take all ingredients
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
@ -334,6 +360,23 @@ public class MultiSellChoose implements IClientIncomingPacket
}
}
}
else if (ingredient.getEnchantmentLevel() > 0)
{
// Take the enchanted item.
final L2ItemInstance destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
if (destroyedItem != null)
{
itemEnchantmentProcessed = true;
iu.addItem(destroyedItem);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addItemName(ingredient.getId());
player.sendPacket(sm);
return;
}
}
else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
{
// Take the enchanted item.
@ -418,8 +461,7 @@ public class MultiSellChoose implements IClientIncomingPacket
else
{
// Give item.
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc);
iu.addItem(addedItem);
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
// Check if the newly given item should be enchanted.
if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getItem().getClass().equals(itemEnchantment.getItem().getClass()))
@ -447,12 +489,15 @@ public class MultiSellChoose implements IClientIncomingPacket
addedItem.addSpecialAbility(_soulCrystalSpecialOptions[i], i + 1, 2, false);
}
}
addedItem.updateDatabase();
// Mark that we have already upgraded the item.
itemEnchantmentProcessed = false;
}
if (product.getEnchantmentLevel() > 0)
{
addedItem.setEnchantLevel(product.getEnchantmentLevel());
addedItem.updateDatabase();
}
if (addedItem.getCount() > 1)
{
@ -474,6 +519,9 @@ public class MultiSellChoose implements IClientIncomingPacket
sm.addItemName(addedItem);
player.sendPacket(sm);
}
// Inventory update.
iu.addItem(addedItem);
}
}
@ -512,7 +560,7 @@ public class MultiSellChoose implements IClientIncomingPacket
* @param totalCount
* @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
*/
private boolean checkIngredients(final L2PcInstance player, PreparedMultisellListHolder list, final PcInventory inventory, final L2Clan clan, final int ingredientId, final long totalCount)
private boolean checkIngredients(L2PcInstance player, PreparedMultisellListHolder list, PcInventory inventory, L2Clan clan, int ingredientId, long totalCount)
{
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
if (specialItem != null)

View File

@ -22,7 +22,6 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.ItemInfo;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
@ -99,14 +98,14 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeH(65535);
}
packet.writeQ(_list.getProductCount(product));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(product.getEnchantmentLevel() > 0 ? product.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeD((int) Math.ceil(product.getChance())); // chance
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);
}
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final L2Item template = ItemTable.getInstance().getTemplate(ingredient.getId());
final ItemInfo displayItemEnchantment = ((itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId())) ? itemEnchantment : null;
@ -114,7 +113,7 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeD(ingredient.getId());
packet.writeH(template != null ? template.getType2() : 65535);
packet.writeQ(_list.getIngredientCount(ingredient));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(ingredient.getEnchantmentLevel() > 0 ? ingredient.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);

View File

@ -88,7 +88,7 @@ public final class MultisellData implements IGameXmlReader
{
if ("item".equalsIgnoreCase(itemNode.getNodeName()))
{
final List<ItemHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> products = new ArrayList<>(1);
final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
@ -98,7 +98,8 @@ public final class MultisellData implements IGameXmlReader
{
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final ItemHolder ingredient = new ItemHolder(id, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel);
if (itemExists(ingredient))
{
@ -115,7 +116,8 @@ public final class MultisellData implements IGameXmlReader
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
if (itemExists(product))
{

View File

@ -28,6 +28,7 @@ import com.l2jmobius.commons.util.Rnd;
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
private final byte _enchantmentLevel;
public ItemChanceHolder(int id, double chance)
{
@ -38,6 +39,14 @@ public class ItemChanceHolder extends ItemHolder
{
super(id, count);
_chance = chance;
_enchantmentLevel = 0;
}
public ItemChanceHolder(int id, double chance, long count, byte enchantmentLevel)
{
super(id, count);
_chance = chance;
_enchantmentLevel = enchantmentLevel;
}
/**
@ -49,6 +58,15 @@ public class ItemChanceHolder extends ItemHolder
return _chance;
}
/**
* Gets the enchant level.
* @return the enchant level of the item contained in this object
*/
public byte getEnchantmentLevel()
{
return _enchantmentLevel;
}
/**
* Calculates a cumulative chance of all given holders. If all holders' chance sum up to 100% or above, there is 100% guarantee a holder will be selected.
* @param holders list of holders to calculate chance from.

View File

@ -29,17 +29,17 @@ import com.l2jmobius.gameserver.model.items.L2Item;
public class MultisellEntryHolder
{
private final boolean _stackable;
private final List<ItemHolder> _ingredients;
private final List<ItemChanceHolder> _ingredients;
private final List<ItemChanceHolder> _products;
public MultisellEntryHolder(List<ItemHolder> ingredients, List<ItemChanceHolder> products)
public MultisellEntryHolder(List<ItemChanceHolder> ingredients, List<ItemChanceHolder> products)
{
_ingredients = Collections.unmodifiableList(ingredients);
_products = Collections.unmodifiableList(products);
_stackable = products.stream().map(i -> ItemTable.getInstance().getTemplate(i.getId())).filter(Objects::nonNull).allMatch(L2Item::isStackable);
}
public final List<ItemHolder> getIngredients()
public final List<ItemChanceHolder> getIngredients()
{
return _ingredients;
}

View File

@ -435,6 +435,21 @@ public class PcInventory extends Inventory
*/
@Override
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
return addItem(process, itemId, count, actor, reference, true);
}
/**
* Adds item in inventory and checks _adena and _ancientAdena
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be added
* @param count : int Quantity of items to be added
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @param update : Update inventory (not used by MultiSellChoose packet / it sends update after finish)
* @return L2ItemInstance corresponding to the new item or the updated item in inventory
*/
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference, boolean update)
{
final L2ItemInstance item = super.addItem(process, itemId, count, actor, reference);
if (item != null)
@ -456,15 +471,18 @@ public class PcInventory extends Inventory
if ((item != null) && (actor != null))
{
// Send inventory update packet
if (!Config.FORCE_INVENTORY_UPDATE)
if (update)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
if (!Config.FORCE_INVENTORY_UPDATE)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
}
}
// Notify to scripts

View File

@ -36,7 +36,6 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.ensoul.EnsoulOption;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
@ -271,6 +270,33 @@ public class MultiSellChoose implements IClientIncomingPacket
// Summarize all item counts into one map. That would include non-stackable items under 1 id and multiple count.
final Map<Integer, Long> itemIdCount = entry.getIngredients().stream().collect(Collectors.toMap(i -> i.getId(), i -> list.getIngredientCount(i), (k1, k2) -> Math.addExact(k1, k2)));
// Check for enchanted level requirements.
for (ItemChanceHolder ingredient : entry.getIngredients())
{
if (ingredient.getEnchantmentLevel() == 0)
{
continue;
}
int found = 0;
for (L2ItemInstance item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
{
if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
{
found++;
}
}
if (found < ingredient.getCount())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemTable.getInstance().getTemplate(ingredient.getId()).getName());
player.sendPacket(sm);
return;
}
itemIdCount.remove(ingredient.getId()); // Since we check now.
}
// Now check if the player has sufficient items in the inventory to cover the ingredients' expences. Take care for non-stackable items like 2 swords to dual.
boolean allOk = true;
for (Entry<Integer, Long> idCount : itemIdCount.entrySet())
@ -288,7 +314,7 @@ public class MultiSellChoose implements IClientIncomingPacket
boolean itemEnchantmentProcessed = (itemEnchantment == null);
// Take all ingredients
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
@ -334,6 +360,23 @@ public class MultiSellChoose implements IClientIncomingPacket
}
}
}
else if (ingredient.getEnchantmentLevel() > 0)
{
// Take the enchanted item.
final L2ItemInstance destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
if (destroyedItem != null)
{
itemEnchantmentProcessed = true;
iu.addItem(destroyedItem);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addItemName(ingredient.getId());
player.sendPacket(sm);
return;
}
}
else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
{
// Take the enchanted item.
@ -418,8 +461,7 @@ public class MultiSellChoose implements IClientIncomingPacket
else
{
// Give item.
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc);
iu.addItem(addedItem);
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
// Check if the newly given item should be enchanted.
if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getItem().getClass().equals(itemEnchantment.getItem().getClass()))
@ -447,12 +489,15 @@ public class MultiSellChoose implements IClientIncomingPacket
addedItem.addSpecialAbility(_soulCrystalSpecialOptions[i], i + 1, 2, false);
}
}
addedItem.updateDatabase();
// Mark that we have already upgraded the item.
itemEnchantmentProcessed = false;
}
if (product.getEnchantmentLevel() > 0)
{
addedItem.setEnchantLevel(product.getEnchantmentLevel());
addedItem.updateDatabase();
}
if (addedItem.getCount() > 1)
{
@ -474,6 +519,9 @@ public class MultiSellChoose implements IClientIncomingPacket
sm.addItemName(addedItem);
player.sendPacket(sm);
}
// Inventory update.
iu.addItem(addedItem);
}
}
@ -512,7 +560,7 @@ public class MultiSellChoose implements IClientIncomingPacket
* @param totalCount
* @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
*/
private boolean checkIngredients(final L2PcInstance player, PreparedMultisellListHolder list, final PcInventory inventory, final L2Clan clan, final int ingredientId, final long totalCount)
private boolean checkIngredients(L2PcInstance player, PreparedMultisellListHolder list, PcInventory inventory, L2Clan clan, int ingredientId, long totalCount)
{
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
if (specialItem != null)

View File

@ -22,7 +22,6 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.ItemInfo;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
@ -100,14 +99,14 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeH(65535);
}
packet.writeQ(_list.getProductCount(product));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(product.getEnchantmentLevel() > 0 ? product.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeD((int) Math.ceil(product.getChance())); // chance
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);
}
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final L2Item template = ItemTable.getInstance().getTemplate(ingredient.getId());
final ItemInfo displayItemEnchantment = ((itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId())) ? itemEnchantment : null;
@ -115,7 +114,7 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeD(ingredient.getId());
packet.writeH(template != null ? template.getType2() : 65535);
packet.writeQ(_list.getIngredientCount(ingredient));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(ingredient.getEnchantmentLevel() > 0 ? ingredient.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);

View File

@ -88,7 +88,7 @@ public final class MultisellData implements IGameXmlReader
{
if ("item".equalsIgnoreCase(itemNode.getNodeName()))
{
final List<ItemHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> products = new ArrayList<>(1);
final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
@ -98,7 +98,8 @@ public final class MultisellData implements IGameXmlReader
{
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final ItemHolder ingredient = new ItemHolder(id, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel);
if (itemExists(ingredient))
{
@ -115,7 +116,8 @@ public final class MultisellData implements IGameXmlReader
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
if (itemExists(product))
{

View File

@ -28,6 +28,7 @@ import com.l2jmobius.commons.util.Rnd;
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
private final byte _enchantmentLevel;
public ItemChanceHolder(int id, double chance)
{
@ -38,6 +39,14 @@ public class ItemChanceHolder extends ItemHolder
{
super(id, count);
_chance = chance;
_enchantmentLevel = 0;
}
public ItemChanceHolder(int id, double chance, long count, byte enchantmentLevel)
{
super(id, count);
_chance = chance;
_enchantmentLevel = enchantmentLevel;
}
/**
@ -49,6 +58,15 @@ public class ItemChanceHolder extends ItemHolder
return _chance;
}
/**
* Gets the enchant level.
* @return the enchant level of the item contained in this object
*/
public byte getEnchantmentLevel()
{
return _enchantmentLevel;
}
/**
* Calculates a cumulative chance of all given holders. If all holders' chance sum up to 100% or above, there is 100% guarantee a holder will be selected.
* @param holders list of holders to calculate chance from.

View File

@ -29,17 +29,17 @@ import com.l2jmobius.gameserver.model.items.L2Item;
public class MultisellEntryHolder
{
private final boolean _stackable;
private final List<ItemHolder> _ingredients;
private final List<ItemChanceHolder> _ingredients;
private final List<ItemChanceHolder> _products;
public MultisellEntryHolder(List<ItemHolder> ingredients, List<ItemChanceHolder> products)
public MultisellEntryHolder(List<ItemChanceHolder> ingredients, List<ItemChanceHolder> products)
{
_ingredients = Collections.unmodifiableList(ingredients);
_products = Collections.unmodifiableList(products);
_stackable = products.stream().map(i -> ItemTable.getInstance().getTemplate(i.getId())).filter(Objects::nonNull).allMatch(L2Item::isStackable);
}
public final List<ItemHolder> getIngredients()
public final List<ItemChanceHolder> getIngredients()
{
return _ingredients;
}

View File

@ -435,6 +435,21 @@ public class PcInventory extends Inventory
*/
@Override
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
return addItem(process, itemId, count, actor, reference, true);
}
/**
* Adds item in inventory and checks _adena and _ancientAdena
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be added
* @param count : int Quantity of items to be added
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @param update : Update inventory (not used by MultiSellChoose packet / it sends update after finish)
* @return L2ItemInstance corresponding to the new item or the updated item in inventory
*/
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference, boolean update)
{
final L2ItemInstance item = super.addItem(process, itemId, count, actor, reference);
if (item != null)
@ -456,15 +471,18 @@ public class PcInventory extends Inventory
if ((item != null) && (actor != null))
{
// Send inventory update packet
if (!Config.FORCE_INVENTORY_UPDATE)
if (update)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
if (!Config.FORCE_INVENTORY_UPDATE)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
}
}
// Notify to scripts

View File

@ -36,7 +36,6 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.ensoul.EnsoulOption;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
@ -271,6 +270,33 @@ public class MultiSellChoose implements IClientIncomingPacket
// Summarize all item counts into one map. That would include non-stackable items under 1 id and multiple count.
final Map<Integer, Long> itemIdCount = entry.getIngredients().stream().collect(Collectors.toMap(i -> i.getId(), i -> list.getIngredientCount(i), (k1, k2) -> Math.addExact(k1, k2)));
// Check for enchanted level requirements.
for (ItemChanceHolder ingredient : entry.getIngredients())
{
if (ingredient.getEnchantmentLevel() == 0)
{
continue;
}
int found = 0;
for (L2ItemInstance item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
{
if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
{
found++;
}
}
if (found < ingredient.getCount())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemTable.getInstance().getTemplate(ingredient.getId()).getName());
player.sendPacket(sm);
return;
}
itemIdCount.remove(ingredient.getId()); // Since we check now.
}
// Now check if the player has sufficient items in the inventory to cover the ingredients' expences. Take care for non-stackable items like 2 swords to dual.
boolean allOk = true;
for (Entry<Integer, Long> idCount : itemIdCount.entrySet())
@ -288,7 +314,7 @@ public class MultiSellChoose implements IClientIncomingPacket
boolean itemEnchantmentProcessed = (itemEnchantment == null);
// Take all ingredients
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
@ -334,6 +360,23 @@ public class MultiSellChoose implements IClientIncomingPacket
}
}
}
else if (ingredient.getEnchantmentLevel() > 0)
{
// Take the enchanted item.
final L2ItemInstance destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
if (destroyedItem != null)
{
itemEnchantmentProcessed = true;
iu.addItem(destroyedItem);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addItemName(ingredient.getId());
player.sendPacket(sm);
return;
}
}
else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
{
// Take the enchanted item.
@ -418,8 +461,7 @@ public class MultiSellChoose implements IClientIncomingPacket
else
{
// Give item.
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc);
iu.addItem(addedItem);
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
// Check if the newly given item should be enchanted.
if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getItem().getClass().equals(itemEnchantment.getItem().getClass()))
@ -447,12 +489,15 @@ public class MultiSellChoose implements IClientIncomingPacket
addedItem.addSpecialAbility(_soulCrystalSpecialOptions[i], i + 1, 2, false);
}
}
addedItem.updateDatabase();
// Mark that we have already upgraded the item.
itemEnchantmentProcessed = false;
}
if (product.getEnchantmentLevel() > 0)
{
addedItem.setEnchantLevel(product.getEnchantmentLevel());
addedItem.updateDatabase();
}
if (addedItem.getCount() > 1)
{
@ -474,6 +519,9 @@ public class MultiSellChoose implements IClientIncomingPacket
sm.addItemName(addedItem);
player.sendPacket(sm);
}
// Inventory update.
iu.addItem(addedItem);
}
}
@ -512,7 +560,7 @@ public class MultiSellChoose implements IClientIncomingPacket
* @param totalCount
* @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
*/
private boolean checkIngredients(final L2PcInstance player, PreparedMultisellListHolder list, final PcInventory inventory, final L2Clan clan, final int ingredientId, final long totalCount)
private boolean checkIngredients(L2PcInstance player, PreparedMultisellListHolder list, PcInventory inventory, L2Clan clan, int ingredientId, long totalCount)
{
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
if (specialItem != null)

View File

@ -22,7 +22,6 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.ItemInfo;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
@ -99,14 +98,14 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeH(65535);
}
packet.writeQ(_list.getProductCount(product));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(product.getEnchantmentLevel() > 0 ? product.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeD((int) Math.ceil(product.getChance())); // chance
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);
}
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final L2Item template = ItemTable.getInstance().getTemplate(ingredient.getId());
final ItemInfo displayItemEnchantment = ((itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId())) ? itemEnchantment : null;
@ -114,7 +113,7 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeD(ingredient.getId());
packet.writeH(template != null ? template.getType2() : 65535);
packet.writeQ(_list.getIngredientCount(ingredient));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(ingredient.getEnchantmentLevel() > 0 ? ingredient.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);

View File

@ -88,7 +88,7 @@ public final class MultisellData implements IGameXmlReader
{
if ("item".equalsIgnoreCase(itemNode.getNodeName()))
{
final List<ItemHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> ingredients = new ArrayList<>(1);
final List<ItemChanceHolder> products = new ArrayList<>(1);
final MultisellEntryHolder entry = new MultisellEntryHolder(ingredients, products);
@ -98,7 +98,8 @@ public final class MultisellData implements IGameXmlReader
{
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final ItemHolder ingredient = new ItemHolder(id, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder ingredient = new ItemChanceHolder(id, 0, count, enchantmentLevel);
if (itemExists(ingredient))
{
@ -115,7 +116,8 @@ public final class MultisellData implements IGameXmlReader
final int id = parseInteger(d.getAttributes(), "id");
final long count = parseLong(d.getAttributes(), "count");
final double chance = parseDouble(d.getAttributes(), "chance", Double.NaN);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count);
final byte enchantmentLevel = parseByte(d.getAttributes(), "enchantmentLevel", (byte) 0);
final ItemChanceHolder product = new ItemChanceHolder(id, chance, count, enchantmentLevel);
if (itemExists(product))
{

View File

@ -28,6 +28,7 @@ import com.l2jmobius.commons.util.Rnd;
public class ItemChanceHolder extends ItemHolder
{
private final double _chance;
private final byte _enchantmentLevel;
public ItemChanceHolder(int id, double chance)
{
@ -38,6 +39,14 @@ public class ItemChanceHolder extends ItemHolder
{
super(id, count);
_chance = chance;
_enchantmentLevel = 0;
}
public ItemChanceHolder(int id, double chance, long count, byte enchantmentLevel)
{
super(id, count);
_chance = chance;
_enchantmentLevel = enchantmentLevel;
}
/**
@ -49,6 +58,15 @@ public class ItemChanceHolder extends ItemHolder
return _chance;
}
/**
* Gets the enchant level.
* @return the enchant level of the item contained in this object
*/
public byte getEnchantmentLevel()
{
return _enchantmentLevel;
}
/**
* Calculates a cumulative chance of all given holders. If all holders' chance sum up to 100% or above, there is 100% guarantee a holder will be selected.
* @param holders list of holders to calculate chance from.

View File

@ -29,17 +29,17 @@ import com.l2jmobius.gameserver.model.items.L2Item;
public class MultisellEntryHolder
{
private final boolean _stackable;
private final List<ItemHolder> _ingredients;
private final List<ItemChanceHolder> _ingredients;
private final List<ItemChanceHolder> _products;
public MultisellEntryHolder(List<ItemHolder> ingredients, List<ItemChanceHolder> products)
public MultisellEntryHolder(List<ItemChanceHolder> ingredients, List<ItemChanceHolder> products)
{
_ingredients = Collections.unmodifiableList(ingredients);
_products = Collections.unmodifiableList(products);
_stackable = products.stream().map(i -> ItemTable.getInstance().getTemplate(i.getId())).filter(Objects::nonNull).allMatch(L2Item::isStackable);
}
public final List<ItemHolder> getIngredients()
public final List<ItemChanceHolder> getIngredients()
{
return _ingredients;
}

View File

@ -435,6 +435,21 @@ public class PcInventory extends Inventory
*/
@Override
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
return addItem(process, itemId, count, actor, reference, true);
}
/**
* Adds item in inventory and checks _adena and _ancientAdena
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be added
* @param count : int Quantity of items to be added
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @param update : Update inventory (not used by MultiSellChoose packet / it sends update after finish)
* @return L2ItemInstance corresponding to the new item or the updated item in inventory
*/
public L2ItemInstance addItem(String process, int itemId, long count, L2PcInstance actor, Object reference, boolean update)
{
final L2ItemInstance item = super.addItem(process, itemId, count, actor, reference);
if (item != null)
@ -456,15 +471,18 @@ public class PcInventory extends Inventory
if ((item != null) && (actor != null))
{
// Send inventory update packet
if (!Config.FORCE_INVENTORY_UPDATE)
if (update)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
if (!Config.FORCE_INVENTORY_UPDATE)
{
final InventoryUpdate playerIU = new InventoryUpdate();
playerIU.addItem(item);
actor.sendInventoryUpdate(playerIU);
}
else
{
actor.sendItemList(false);
}
}
// Notify to scripts

View File

@ -36,7 +36,6 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.ensoul.EnsoulOption;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
@ -271,6 +270,33 @@ public class MultiSellChoose implements IClientIncomingPacket
// Summarize all item counts into one map. That would include non-stackable items under 1 id and multiple count.
final Map<Integer, Long> itemIdCount = entry.getIngredients().stream().collect(Collectors.toMap(i -> i.getId(), i -> list.getIngredientCount(i), (k1, k2) -> Math.addExact(k1, k2)));
// Check for enchanted level requirements.
for (ItemChanceHolder ingredient : entry.getIngredients())
{
if (ingredient.getEnchantmentLevel() == 0)
{
continue;
}
int found = 0;
for (L2ItemInstance item : inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()))
{
if (item.getEnchantLevel() >= ingredient.getEnchantmentLevel())
{
found++;
}
}
if (found < ingredient.getCount())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addString("+" + ingredient.getEnchantmentLevel() + " " + ItemTable.getInstance().getTemplate(ingredient.getId()).getName());
player.sendPacket(sm);
return;
}
itemIdCount.remove(ingredient.getId()); // Since we check now.
}
// Now check if the player has sufficient items in the inventory to cover the ingredients' expences. Take care for non-stackable items like 2 swords to dual.
boolean allOk = true;
for (Entry<Integer, Long> idCount : itemIdCount.entrySet())
@ -288,7 +314,7 @@ public class MultiSellChoose implements IClientIncomingPacket
boolean itemEnchantmentProcessed = (itemEnchantment == null);
// Take all ingredients
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final long totalCount = Math.multiplyExact(list.getIngredientCount(ingredient), _amount);
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredient.getId());
@ -334,6 +360,23 @@ public class MultiSellChoose implements IClientIncomingPacket
}
}
}
else if (ingredient.getEnchantmentLevel() > 0)
{
// Take the enchanted item.
final L2ItemInstance destroyedItem = inventory.destroyItem("Multisell", inventory.getAllItemsByItemId(ingredient.getId(), ingredient.getEnchantmentLevel()).iterator().next(), totalCount, player, npc);
if (destroyedItem != null)
{
itemEnchantmentProcessed = true;
iu.addItem(destroyedItem);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_NEED_A_N_S1);
sm.addItemName(ingredient.getId());
player.sendPacket(sm);
return;
}
}
else if (!itemEnchantmentProcessed && (itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId()))
{
// Take the enchanted item.
@ -418,8 +461,7 @@ public class MultiSellChoose implements IClientIncomingPacket
else
{
// Give item.
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc);
iu.addItem(addedItem);
final L2ItemInstance addedItem = inventory.addItem("Multisell", product.getId(), totalCount, player, npc, false);
// Check if the newly given item should be enchanted.
if (itemEnchantmentProcessed && list.isMaintainEnchantment() && (itemEnchantment != null) && addedItem.isEquipable() && addedItem.getItem().getClass().equals(itemEnchantment.getItem().getClass()))
@ -447,12 +489,15 @@ public class MultiSellChoose implements IClientIncomingPacket
addedItem.addSpecialAbility(_soulCrystalSpecialOptions[i], i + 1, 2, false);
}
}
addedItem.updateDatabase();
// Mark that we have already upgraded the item.
itemEnchantmentProcessed = false;
}
if (product.getEnchantmentLevel() > 0)
{
addedItem.setEnchantLevel(product.getEnchantmentLevel());
addedItem.updateDatabase();
}
if (addedItem.getCount() > 1)
{
@ -474,6 +519,9 @@ public class MultiSellChoose implements IClientIncomingPacket
sm.addItemName(addedItem);
player.sendPacket(sm);
}
// Inventory update.
iu.addItem(addedItem);
}
}
@ -512,7 +560,7 @@ public class MultiSellChoose implements IClientIncomingPacket
* @param totalCount
* @return {@code false} if ingredient amount is not enough, {@code true} otherwise.
*/
private boolean checkIngredients(final L2PcInstance player, PreparedMultisellListHolder list, final PcInventory inventory, final L2Clan clan, final int ingredientId, final long totalCount)
private boolean checkIngredients(L2PcInstance player, PreparedMultisellListHolder list, PcInventory inventory, L2Clan clan, int ingredientId, long totalCount)
{
final SpecialItemType specialItem = SpecialItemType.getByClientId(ingredientId);
if (specialItem != null)

View File

@ -22,7 +22,6 @@ import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.model.ItemInfo;
import com.l2jmobius.gameserver.model.holders.ItemChanceHolder;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.MultisellEntryHolder;
import com.l2jmobius.gameserver.model.holders.PreparedMultisellListHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
@ -100,14 +99,14 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeH(65535);
}
packet.writeQ(_list.getProductCount(product));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(product.getEnchantmentLevel() > 0 ? product.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeD((int) Math.ceil(product.getChance())); // chance
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);
}
for (ItemHolder ingredient : entry.getIngredients())
for (ItemChanceHolder ingredient : entry.getIngredients())
{
final L2Item template = ItemTable.getInstance().getTemplate(ingredient.getId());
final ItemInfo displayItemEnchantment = ((itemEnchantment != null) && (itemEnchantment.getItem().getId() == ingredient.getId())) ? itemEnchantment : null;
@ -115,7 +114,7 @@ public final class MultiSellList extends AbstractItemPacket
packet.writeD(ingredient.getId());
packet.writeH(template != null ? template.getType2() : 65535);
packet.writeQ(_list.getIngredientCount(ingredient));
packet.writeH(displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
packet.writeH(ingredient.getEnchantmentLevel() > 0 ? ingredient.getEnchantmentLevel() : displayItemEnchantment != null ? displayItemEnchantment.getEnchantLevel() : 0); // enchant level
writeItemAugment(packet, displayItemEnchantment);
writeItemElemental(packet, displayItemEnchantment);
writeItemEnsoulOptions(packet, displayItemEnchantment);