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; | ||||
| @@ -358,6 +360,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) | ||||
| 							{ | ||||
| @@ -391,6 +395,12 @@ public class RequestEnchantItem implements ClientPacket | ||||
| 								return; | ||||
| 							} | ||||
| 							 | ||||
| 							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())); | ||||
| 							} | ||||
| 							 | ||||
| 							World.getInstance().removeObject(item); | ||||
| 							 | ||||
| 							int count = 0; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 MobiusDevelopment
					MobiusDevelopment