Addition of rewards on enchant failure.
Contributed by Index.
This commit is contained in:
		@@ -1,4 +1,30 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/CrystallizableItems.xsd">
 | 
			
		||||
	<!-- Templates for generating automatically crystallization data. Chance is multiplied by the amount of crystals the item template has. -->
 | 
			
		||||
	<!-- Templates for generating automatically crystallization data. -->
 | 
			
		||||
	<itemsOnEnchantFailure>
 | 
			
		||||
		<weapon>
 | 
			
		||||
			<item id="91462" enchant="7" chance="100" amountD="1" amountC="2" amountB="3" amountA="5" amountS="15" />
 | 
			
		||||
			<item id="91462" enchant="8" chance="100" amountD="2" amountC="3" amountB="4" amountA="6" amountS="18" />
 | 
			
		||||
			<item id="91462" enchant="9" chance="100" amountD="3" amountC="4" amountB="5" amountA="7" amountS="21" />
 | 
			
		||||
			<item id="91462" enchant="10" chance="100" amountD="4" amountC="7" amountB="8" amountA="12" amountS="25" />
 | 
			
		||||
			<item id="91462" enchant="11" chance="100" amountD="5" amountC="8" amountB="9" amountA="13" amountS="28" />
 | 
			
		||||
			<item id="91462" enchant="12" chance="100" amountD="6" amountC="9" amountB="10" amountA="14" amountS="29" />
 | 
			
		||||
			<item id="91462" enchant="13" chance="100" amountD="7" amountC="12" amountB="13" amountA="19" amountS="30" />
 | 
			
		||||
			<item id="91462" enchant="14" chance="100" amountD="8" amountC="13" amountB="14" amountA="20" amountS="31" />
 | 
			
		||||
			<item id="91462" enchant="15" chance="100" amountD="9" amountC="14" amountB="15" amountA="21" amountS="32" />
 | 
			
		||||
			<item id="91462" enchant="16" chance="100" amountD="10" amountC="17" amountB="18" amountA="26" amountS="33" />
 | 
			
		||||
			<item id="91462" enchant="17" chance="100" amountD="11" amountC="18" amountB="19" amountA="27" amountS="34" />
 | 
			
		||||
			<item id="91462" enchant="18" chance="100" amountD="12" amountC="19" amountB="20" amountA="28" amountS="35" />
 | 
			
		||||
			<item id="91462" enchant="19" chance="100" amountD="14" amountC="25" amountB="28" amountA="35" amountS="36" />
 | 
			
		||||
		</weapon>
 | 
			
		||||
		<armor>
 | 
			
		||||
			<item id="91463" enchant="6" chance="100" amountD="1" amountC="2" amountB="3" amountA="5" amountS="10" />
 | 
			
		||||
			<item id="91463" enchant="7" chance="100" amountD="2" amountC="3" amountB="4" amountA="6" amountS="15" />
 | 
			
		||||
			<item id="91463" enchant="8" chance="100" amountD="3" amountC="4" amountB="5" amountA="7" amountS="20" />
 | 
			
		||||
			<item id="91463" enchant="9" chance="100" amountD="5" amountC="7" amountB="9" amountA="13" amountS="25" />
 | 
			
		||||
			<item id="91463" enchant="10" chance="100" amountD="6" amountC="8" amountB="10" amountA="14" amountS="27"/>
 | 
			
		||||
			<item id="91463" enchant="11" chance="100" amountD="7" amountC="9" amountB="11" amountA="16" amountS="28" />
 | 
			
		||||
			<item id="91463" enchant="12" chance="100" amountD="12" amountC="15" amountB="19" amountA="26" amountS="30" />
 | 
			
		||||
		</armor>
 | 
			
		||||
	</itemsOnEnchantFailure>
 | 
			
		||||
</list>
 | 
			
		||||
@@ -43,6 +43,48 @@
 | 
			
		||||
						</xs:sequence>
 | 
			
		||||
					</xs:complexType>
 | 
			
		||||
				</xs:element>
 | 
			
		||||
				<xs:element name="itemsOnEnchantFailure" maxOccurs="unbounded" minOccurs="0">
 | 
			
		||||
					<xs:complexType>
 | 
			
		||||
						<xs:sequence>
 | 
			
		||||
							<xs:element name="weapon" maxOccurs="1" minOccurs="0">
 | 
			
		||||
								<xs:complexType>
 | 
			
		||||
									<xs:sequence>
 | 
			
		||||
										<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
 | 
			
		||||
											<xs:complexType>
 | 
			
		||||
												<xs:attribute type="xs:int" name="id" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="enchant" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:float" name="chance" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountD" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountC" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountB" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountA" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountS" use="required" />
 | 
			
		||||
											</xs:complexType>
 | 
			
		||||
										</xs:element>
 | 
			
		||||
									</xs:sequence>
 | 
			
		||||
								</xs:complexType>
 | 
			
		||||
							</xs:element>
 | 
			
		||||
							<xs:element name="armor" maxOccurs="1" minOccurs="0">
 | 
			
		||||
								<xs:complexType>
 | 
			
		||||
									<xs:sequence>
 | 
			
		||||
										<xs:element name="item" maxOccurs="unbounded" minOccurs="0">
 | 
			
		||||
											<xs:complexType>
 | 
			
		||||
												<xs:attribute type="xs:int" name="id" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="enchant" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:float" name="chance" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountD" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountC" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountB" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountA" use="required" />
 | 
			
		||||
												<xs:attribute type="xs:int" name="amountS" use="required" />
 | 
			
		||||
											</xs:complexType>
 | 
			
		||||
										</xs:element>
 | 
			
		||||
									</xs:sequence>
 | 
			
		||||
								</xs:complexType>
 | 
			
		||||
							</xs:element>
 | 
			
		||||
						</xs:sequence>
 | 
			
		||||
					</xs:complexType>
 | 
			
		||||
				</xs:element>
 | 
			
		||||
			</xs:sequence>
 | 
			
		||||
		</xs:complexType>
 | 
			
		||||
	</xs:element>
 | 
			
		||||
 
 | 
			
		||||
@@ -31,16 +31,19 @@ import org.w3c.dom.Node;
 | 
			
		||||
import org.l2jmobius.commons.util.IXmlReader;
 | 
			
		||||
import org.l2jmobius.gameserver.data.ItemTable;
 | 
			
		||||
import org.l2jmobius.gameserver.enums.CrystallizationType;
 | 
			
		||||
import org.l2jmobius.gameserver.model.StatSet;
 | 
			
		||||
import org.l2jmobius.gameserver.model.actor.Player;
 | 
			
		||||
import org.l2jmobius.gameserver.model.holders.CrystallizationDataHolder;
 | 
			
		||||
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.Armor;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.ItemTemplate;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.Weapon;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.enchant.RewardItemsOnFailure;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.instance.Item;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.type.CrystalType;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author UnAfraid
 | 
			
		||||
 * @author UnAfraid, Index
 | 
			
		||||
 */
 | 
			
		||||
public class ItemCrystallizationData implements IXmlReader
 | 
			
		||||
{
 | 
			
		||||
@@ -49,6 +52,9 @@ public class ItemCrystallizationData implements IXmlReader
 | 
			
		||||
	private final Map<CrystalType, Map<CrystallizationType, List<ItemChanceHolder>>> _crystallizationTemplates = new EnumMap<>(CrystalType.class);
 | 
			
		||||
	private final Map<Integer, CrystallizationDataHolder> _items = new HashMap<>();
 | 
			
		||||
	
 | 
			
		||||
	private RewardItemsOnFailure _weaponDestroyGroup = new RewardItemsOnFailure();
 | 
			
		||||
	private RewardItemsOnFailure _armorDestroyGroup = new RewardItemsOnFailure();
 | 
			
		||||
	
 | 
			
		||||
	protected ItemCrystallizationData()
 | 
			
		||||
	{
 | 
			
		||||
		load();
 | 
			
		||||
@@ -63,12 +69,32 @@ public class ItemCrystallizationData implements IXmlReader
 | 
			
		||||
			_crystallizationTemplates.put(crystalType, new EnumMap<>(CrystallizationType.class));
 | 
			
		||||
		}
 | 
			
		||||
		_items.clear();
 | 
			
		||||
		
 | 
			
		||||
		_weaponDestroyGroup = new RewardItemsOnFailure();
 | 
			
		||||
		_armorDestroyGroup = new RewardItemsOnFailure();
 | 
			
		||||
		
 | 
			
		||||
		parseDatapackFile("data/CrystallizableItems.xml");
 | 
			
		||||
		LOGGER.info(getClass().getSimpleName() + ": Loaded " + _crystallizationTemplates.size() + " crystallization templates.");
 | 
			
		||||
		LOGGER.info(getClass().getSimpleName() + ": Loaded " + _items.size() + " pre-defined crystallizable items.");
 | 
			
		||||
		
 | 
			
		||||
		if (_crystallizationTemplates.size() > 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOGGER.info(getClass().getSimpleName() + ": Loaded " + _crystallizationTemplates.size() + " crystallization templates.");
 | 
			
		||||
		}
 | 
			
		||||
		if (_items.size() > 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOGGER.info(getClass().getSimpleName() + ": Loaded " + _items.size() + " pre-defined crystallizable items.");
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		// Generate remaining data.
 | 
			
		||||
		generateCrystallizationData();
 | 
			
		||||
		
 | 
			
		||||
		if (_weaponDestroyGroup.size() > 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOGGER.info(getClass().getSimpleName() + ": Loaded " + _weaponDestroyGroup.size() + " weapon enchant failure rewards.");
 | 
			
		||||
		}
 | 
			
		||||
		if (_armorDestroyGroup.size() > 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOGGER.info(getClass().getSimpleName() + ": Loaded " + _armorDestroyGroup.size() + " armor enchant failure rewards.");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Override
 | 
			
		||||
@@ -128,6 +154,20 @@ public class ItemCrystallizationData implements IXmlReader
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					else if ("itemsOnEnchantFailure".equals(o.getNodeName()))
 | 
			
		||||
					{
 | 
			
		||||
						for (Node d = o.getFirstChild(); d != null; d = d.getNextSibling())
 | 
			
		||||
						{
 | 
			
		||||
							if ("armor".equalsIgnoreCase(d.getNodeName()))
 | 
			
		||||
							{
 | 
			
		||||
								_armorDestroyGroup = getFormedHolder(d);
 | 
			
		||||
							}
 | 
			
		||||
							else if ("weapon".equalsIgnoreCase(d.getNodeName()))
 | 
			
		||||
							{
 | 
			
		||||
								_weaponDestroyGroup = getFormedHolder(d);
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -179,7 +219,11 @@ public class ItemCrystallizationData implements IXmlReader
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		LOGGER.info(getClass().getSimpleName() + ": Generated " + (_items.size() - previousCount) + " crystallizable items from templates.");
 | 
			
		||||
		final int generated = _items.size() - previousCount;
 | 
			
		||||
		if (generated > 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOGGER.info(getClass().getSimpleName() + ": Generated " + generated + " crystallizable items from templates.");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public List<ItemChanceHolder> getCrystallizationTemplate(CrystalType crystalType, CrystallizationType crystallizationType)
 | 
			
		||||
@@ -235,6 +279,49 @@ public class ItemCrystallizationData implements IXmlReader
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private RewardItemsOnFailure getFormedHolder(Node node)
 | 
			
		||||
	{
 | 
			
		||||
		final RewardItemsOnFailure holder = new RewardItemsOnFailure();
 | 
			
		||||
		for (Node z = node.getFirstChild(); z != null; z = z.getNextSibling())
 | 
			
		||||
		{
 | 
			
		||||
			if ("item".equals(z.getNodeName()))
 | 
			
		||||
			{
 | 
			
		||||
				final StatSet failItems = new StatSet(parseAttributes(z));
 | 
			
		||||
				final int itemId = failItems.getInt("id");
 | 
			
		||||
				final int enchantLevel = failItems.getInt("enchant");
 | 
			
		||||
				final double chance = failItems.getDouble("chance");
 | 
			
		||||
				for (CrystalType grade : CrystalType.values())
 | 
			
		||||
				{
 | 
			
		||||
					final long count = failItems.getLong("amount" + grade.name(), Integer.MIN_VALUE);
 | 
			
		||||
					if (count == Integer.MIN_VALUE)
 | 
			
		||||
					{
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
					
 | 
			
		||||
					holder.addItemToHolder(itemId, grade, enchantLevel, count, chance);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return holder;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public ItemChanceHolder getItemOnDestroy(Player player, Item item)
 | 
			
		||||
	{
 | 
			
		||||
		if ((player == null) || (item == null))
 | 
			
		||||
		{
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		final RewardItemsOnFailure holder = item.isWeapon() ? _weaponDestroyGroup : _armorDestroyGroup;
 | 
			
		||||
		final CrystalType grade = item.getTemplate().getCrystalTypePlus();
 | 
			
		||||
		if (holder.checkIfRewardUnavailable(grade, item.getEnchantLevel()))
 | 
			
		||||
		{
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return holder.getRewardItem(grade, item.getEnchantLevel());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * Gets the single instance of ItemCrystalizationData.
 | 
			
		||||
	 * @return single instance of ItemCrystalizationData
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
/*
 | 
			
		||||
 * This file is part of the L2J Mobius project.
 | 
			
		||||
 * 
 | 
			
		||||
 * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package org.l2jmobius.gameserver.model.item.enchant;
 | 
			
		||||
 | 
			
		||||
import java.util.EnumMap;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.type.CrystalType;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @author Index
 | 
			
		||||
 */
 | 
			
		||||
public class RewardItemsOnFailure
 | 
			
		||||
{
 | 
			
		||||
	private final Map<CrystalType, Map<Integer, ItemChanceHolder>> _rewards = new EnumMap<>(CrystalType.class);
 | 
			
		||||
	private int _minEnchantLevel = Integer.MAX_VALUE;
 | 
			
		||||
	private int _maxEnchantLevel = Integer.MIN_VALUE;
 | 
			
		||||
	
 | 
			
		||||
	public RewardItemsOnFailure()
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public void addItemToHolder(int itemId, CrystalType grade, int enchantLevel, long count, double chance)
 | 
			
		||||
	{
 | 
			
		||||
		final ItemChanceHolder item = new ItemChanceHolder(itemId, chance, count);
 | 
			
		||||
		_rewards.computeIfAbsent(grade, v -> new HashMap<>()).put(enchantLevel, item);
 | 
			
		||||
		_minEnchantLevel = Math.min(_minEnchantLevel, enchantLevel);
 | 
			
		||||
		_maxEnchantLevel = Math.max(_maxEnchantLevel, enchantLevel);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public ItemChanceHolder getRewardItem(CrystalType grade, int enchantLevel)
 | 
			
		||||
	{
 | 
			
		||||
		return _rewards.getOrDefault(grade, new HashMap<>()).getOrDefault(enchantLevel, null);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public boolean checkIfRewardUnavailable(CrystalType grade, int enchantLevel)
 | 
			
		||||
	{
 | 
			
		||||
		// reversed available
 | 
			
		||||
		if (_minEnchantLevel > enchantLevel)
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (_maxEnchantLevel < enchantLevel)
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (!_rewards.containsKey(grade))
 | 
			
		||||
		{
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		return !_rewards.get(grade).containsKey(enchantLevel);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public int size()
 | 
			
		||||
	{
 | 
			
		||||
		int count = 0;
 | 
			
		||||
		for (Map<Integer, ItemChanceHolder> rewards : _rewards.values())
 | 
			
		||||
		{
 | 
			
		||||
			count += rewards.size();
 | 
			
		||||
		}
 | 
			
		||||
		return count;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -22,11 +22,13 @@ import org.l2jmobius.Config;
 | 
			
		||||
import org.l2jmobius.commons.network.ReadablePacket;
 | 
			
		||||
import org.l2jmobius.commons.util.Rnd;
 | 
			
		||||
import org.l2jmobius.gameserver.data.xml.EnchantItemData;
 | 
			
		||||
import org.l2jmobius.gameserver.data.xml.ItemCrystallizationData;
 | 
			
		||||
import org.l2jmobius.gameserver.enums.ItemSkillType;
 | 
			
		||||
import org.l2jmobius.gameserver.enums.UserInfoType;
 | 
			
		||||
import org.l2jmobius.gameserver.model.World;
 | 
			
		||||
import org.l2jmobius.gameserver.model.actor.Player;
 | 
			
		||||
import org.l2jmobius.gameserver.model.actor.request.EnchantItemRequest;
 | 
			
		||||
import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.ItemTemplate;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.enchant.EnchantResultType;
 | 
			
		||||
import org.l2jmobius.gameserver.model.item.enchant.EnchantScroll;
 | 
			
		||||
@@ -353,6 +355,8 @@ public class RequestEnchantItem implements ClientPacket
 | 
			
		||||
						}
 | 
			
		||||
						else
 | 
			
		||||
						{
 | 
			
		||||
							final ItemChanceHolder destroyReward = ItemCrystallizationData.getInstance().getItemOnDestroy(player, item);
 | 
			
		||||
							
 | 
			
		||||
							// enchant failed, destroy item
 | 
			
		||||
							if (player.getInventory().destroyItem("Enchant", item, player, null) == null)
 | 
			
		||||
							{
 | 
			
		||||
@@ -420,6 +424,12 @@ public class RequestEnchantItem implements ClientPacket
 | 
			
		||||
								player.sendPacket(new EnchantResult(EnchantResult.FAIL, crystalId, count));
 | 
			
		||||
							}
 | 
			
		||||
							
 | 
			
		||||
							if ((destroyReward != null) && (Rnd.get(100) < destroyReward.getChance()))
 | 
			
		||||
							{
 | 
			
		||||
								player.addItem("Enchant", destroyReward.getId(), destroyReward.getCount(), null, true);
 | 
			
		||||
								player.sendPacket(new EnchantResult(EnchantResult.FAIL, destroyReward.getId(), (int) destroyReward.getCount()));
 | 
			
		||||
							}
 | 
			
		||||
							
 | 
			
		||||
							if (Config.LOG_ITEM_ENCHANTS)
 | 
			
		||||
							{
 | 
			
		||||
								final StringBuilder sb = new StringBuilder();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user