12-05-2011, 12:58 PM
Выкладываю простенький класс для феникса, для поддержки самопальных свитков заточки (например поддержки свитков для заточки посоха в эвенте Master of Enchanting или свитки для точения Olf's T-Shirt).
Изначально в пакетах заточки в фениксе имеется поддержка заточек посоха для эвента Master of Enchanting, можно и для других комбинаций добавить, но сами понимаете - код получается из-за всех этих условий жутко громоздким и нечитабельным.
Собственно из-за этого я где-то с месяц назад и набросал для своего удобства класс, который поддерживает неограниченное количество самопальных комбинаций "свиток + затачиваемые свитком вещи", не усложняет сильно серверные пакеты заточки и легко настраивается через датапак.
итак, вот сам класс (куда положить в ядре - видно по заголовку):
а в датапак кладем xml-файл с названием enchant_scrolls.xml и примерно с таким содержанием (как обявлять новые комбинации понятно из комментариев в начале):
Изменения, которые еще требуется сделать в ядре сервера:
Ну и не забываем добавить в этих классах в импорты класс EnchantScrollData.
Так же стоит почистить пакеты RequestEnchantItem и RequestExTryToPutEnchantTargetItem от уже ненужных проверок на соответствие вещей на свиток и посох из эвента Master of Enchanting - все равно это будет после всего этого мертвым кодом.
З.Ы. и да, просьба к определенным личностям не тырить шару и не продавать ее потом как свою "собственноручно написанную разработку, которую вы можете купить только у нас" - намек думаю понятно кому адресован
Изначально в пакетах заточки в фениксе имеется поддержка заточек посоха для эвента Master of Enchanting, можно и для других комбинаций добавить, но сами понимаете - код получается из-за всех этих условий жутко громоздким и нечитабельным.
Собственно из-за этого я где-то с месяц назад и набросал для своего удобства класс, который поддерживает неограниченное количество самопальных комбинаций "свиток + затачиваемые свитком вещи", не усложняет сильно серверные пакеты заточки и легко настраивается через датапак.
итак, вот сам класс (куда положить в ядре - видно по заголовку):
Код:
package l2p.gameserver.tables;
import java.io.File;
import java.util.HashMap;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import l2p.Config;
import l2p.extensions.multilang.CustomMessage;
import l2p.gameserver.cache.Msg;
import l2p.gameserver.model.L2Player;
import l2p.gameserver.model.items.L2ItemInstance;
import l2p.gameserver.model.items.PcInventory;
import l2p.gameserver.serverpackets.EnchantResult;
import l2p.gameserver.serverpackets.ExPutEnchantTargetItemResult;
import l2p.gameserver.serverpackets.InventoryUpdate;
import l2p.gameserver.serverpackets.SystemMessage;
import l2p.gameserver.tables.ItemTable;
import l2p.gameserver.tables.SkillTable;
import l2p.gameserver.templates.L2Item;
import l2p.util.GArray;
import l2p.util.Log;
import l2p.util.Rnd;
import l2p.util.XMLUtil;
public class EnchantScrollData
{
private static final String xmlFile = "data/enchant_scrolls.xml";
private static EnchantScrollData _instance;
private static HashMap<Integer, ScrollData> _data = new HashMap<Integer, ScrollData>();
private static Logger _log = Logger.getLogger(EnchantScrollData.class.getName());
private static final class ScrollData
{
public int chance = 0;
public int action_of_fail = 0;
public int safe_enchant = 0;
public int max_enchant = 0;
public int premium_bonus = 0;
public GArray<Integer> items = new GArray<Integer>();
}
public static EnchantScrollData getInstance()
{
if(_instance == null)
_instance = new EnchantScrollData();
return _instance;
}
public EnchantScrollData()
{
loadXml();
}
private void loadXml()
{
final File localFile = new File(xmlFile);
if (!localFile.exists())
{
System.out.println("File '" + xmlFile + "' not found!");
return;
}
Document localDocument = null;
try
{
final DocumentBuilderFactory localDocumentBuilderFactory = DocumentBuilderFactory.newInstance();
localDocumentBuilderFactory.setValidating(false);
localDocumentBuilderFactory.setIgnoringComments(true);
localDocument = localDocumentBuilderFactory.newDocumentBuilder().parse(localFile);
}
catch (final Exception e)
{
e.printStackTrace();
}
try
{
parseXml(localDocument);
}
catch (final Exception e)
{
e.printStackTrace();
}
}
private void parseXml(final Document doc)
{
for (Node il = doc.getFirstChild(); il != null; il = il.getNextSibling())
if ("list".equalsIgnoreCase(il.getNodeName()))
for (Node area = il.getFirstChild(); area != null; area = area.getNextSibling())
{
if ("scroll".equalsIgnoreCase(area.getNodeName()))
{
ScrollData data = new ScrollData();
int scrollId = XMLUtil.getAttributeIntValue(area, "id", 0);
if (scrollId > 0 && ItemTable.getInstance().isExists(scrollId))
{
data.chance = XMLUtil.getAttributeIntValue(area, "chance", 66);
data.action_of_fail = XMLUtil.getAttributeIntValue(area, "action_of_fail", 0);
data.safe_enchant = XMLUtil.getAttributeIntValue(area, "safe_enchant", 3);
data.max_enchant = XMLUtil.getAttributeIntValue(area, "max_enchant", Config.ENCHANT_MAX);
data.premium_bonus = XMLUtil.getAttributeIntValue(area, "premium_bonus", 0);
String temp = XMLUtil.getAttributeValue(area, "item_to_enchant");
if (temp != null && !temp.isEmpty())
{
String items[] = temp.split(",");
for (String item : items)
{
int itemId = Integer.parseInt(item);
if (itemId > 0 && ItemTable.getInstance().isExists(itemId))
data.items.add(itemId);
else
_log.warning("EnchantScrollData: Not found item for enchant with id = " + itemId + ", scroll id = " + scrollId);
}
}
if (data.items.size() == 0)
_log.warning("EnchantScrollData: not specified enchanting items for scroll with id = " + scrollId);
else
_data.put(scrollId, data);
}
else
_log.warning("EnchantScrollData: Not found scroll with id = " + scrollId);
}
}
_log.info("EnchantScrollData: Loaded " + _data.size() + " custom enchant scrolls.");
}
public boolean requestEnchantItem(L2Player player, PcInventory inventory, L2ItemInstance scroll, L2ItemInstance item)
{
if (player == null || scroll == null || item == null || !_data.containsKey(scroll.getItemId()))
return false;
ScrollData data = _data.get(scroll.getItemId());
if (!data.items.contains(item.getItemId()))
{
player.sendPacket(EnchantResult.CANCEL);
player.sendPacket(Msg.INAPPROPRIATE_ENCHANT_CONDITIONS);
player.sendActionFailed();
return true;
}
if (item.getLocation() != L2ItemInstance.ItemLocation.INVENTORY && item.getLocation() != L2ItemInstance.ItemLocation.PAPERDOLL)
{
player.sendPacket(EnchantResult.CANCEL);
player.sendPacket(Msg.INAPPROPRIATE_ENCHANT_CONDITIONS);
player.sendActionFailed();
return true;
}
if (player.getPrivateStoreType() != L2Player.STORE_PRIVATE_NONE)
{
player.sendPacket(EnchantResult.CANCEL);
player.sendPacket(Msg.YOU_CANNOT_PRACTICE_ENCHANTING_WHILE_OPERATING_A_PRIVATE_STORE_OR_PRIVATE_MANUFACTURING_WORKSHOP);
player.sendActionFailed();
return true;
}
if (item.isStackable() || (scroll = inventory.getItemByObjectId(scroll.getObjectId())) == null)
{
player.sendPacket(EnchantResult.CANCEL);
player.sendActionFailed();
return true;
}
if (item.getOwnerId() != player.getObjectId())
{
player.sendPacket(EnchantResult.CANCEL);
player.sendPacket(Msg.INAPPROPRIATE_ENCHANT_CONDITIONS);
player.sendActionFailed();
return true;
}
if (item.getEnchantLevel() >= data.max_enchant)
{
player.sendPacket(EnchantResult.CANCEL);
player.sendMessage(new CustomMessage("l2p.gameserver.clientpackets.RequestEnchantItem.MaxLevel", player));
player.sendActionFailed();
return true;
}
L2ItemInstance removedScroll = null;
synchronized (inventory)
{
removedScroll = inventory.destroyItem(scroll, 1, true);
}
if (removedScroll == null)
{
player.sendPacket(EnchantResult.CANCEL);
player.sendActionFailed();
return true;
}
int itemType = item.getItem().getType2();
double chance = item.getEnchantLevel() < data.safe_enchant ? 100 : data.chance;
if (data.premium_bonus > 0 && player.getNetConnection().getBonus() > 1)
chance += data.premium_bonus;
chance = Math.min(chance, 100D);
Log.add(player.getName() + "|Trying to enchant|" + item.getItemId() + "|+" + item.getEnchantLevel() + "|" + item.getObjectId(), "enchants");
if (Rnd.chance(chance))
{
item.setEnchantLevel(item.getEnchantLevel() + 1);
item.updateDatabase();
player.sendPacket(new InventoryUpdate().addModifiedItem(item));
Log.add(player.getName() + "|Successfully enchanted|" + item.getItemId() + "|to+" + item.getEnchantLevel() + "|" + chance, "enchants");
Log.LogItem(player, Log.EnchantItem, item);
player.sendPacket(EnchantResult.SUCESS);
if (item.getEnchantLevel() >= (itemType == L2Item.TYPE2_WEAPON ? 6 : 5))
{
player.enableSkill(21006);
player.altUseSkill(SkillTable.getInstance().getInfo(21006, 1), player);
player.broadcastPacket(new SystemMessage(SystemMessage.C1_HAS_SUCCESSFULY_ENCHANTED_A__S2_S3).addName(player).addNumber(item.getEnchantLevel()).addItemName(item.getItemId()));
}
}
else
{
Log.add(player.getName() + "|Failed to enchant|" + item.getItemId() + "|+" + item.getEnchantLevel() + "|" + chance, "enchants");
if (data.action_of_fail == 0)
{
if (item.isEquipped())
inventory.unEquipItemInSlot(item.getEquipSlot());
L2ItemInstance destroyedItem = inventory.destroyItem(item.getObjectId(), 1, true);
if (destroyedItem == null)
{
_log.warning("failed to destroy " + item.getObjectId() + " after unsuccessful enchant attempt by char " + player.getName());
player.sendActionFailed();
return true;
}
Log.LogItem(player, Log.EnchantItemFail, item);
player.sendPacket(EnchantResult.FAILED_NO_CRYSTALS);
player.refreshExpertisePenalty();
}
else if (data.action_of_fail == 1)
{
item.setEnchantLevel(0);
player.sendPacket(new InventoryUpdate().addModifiedItem(item));
player.sendPacket(Msg.FAILED_IN_BLESSED_ENCHANT_THE_ENCHANT_VALUE_OF_THE_ITEM_BECAME_0);
player.sendPacket(EnchantResult.BLESSED_FAILED);
}
else if (data.action_of_fail == 2)
{
player.sendPacket(EnchantResult.ANCIENT_FAILED);
}
}
player.refreshOverloaded();
player.setEnchantScroll(null);
player.sendChanges();
return true;
}
public boolean requestExTryToPutEnchantTargetItem(L2Player player, PcInventory inventory, L2ItemInstance scroll, L2ItemInstance item)
{
if (player == null || scroll == null || item == null || !_data.containsKey(scroll.getItemId()))
return false;
ScrollData data = _data.get(scroll.getItemId());
if (!data.items.contains(item.getItemId()))
{
player.sendActionFailed();
player.sendPacket(Msg.INAPPROPRIATE_ENCHANT_CONDITIONS);
return true;
}
if (item.isStackable())
{
player.sendActionFailed();
player.sendPacket(Msg.DOES_NOT_FIT_STRENGTHENING_CONDITIONS_OF_THE_SCROLL);
return true;
}
if (item.getLocation() != L2ItemInstance.ItemLocation.INVENTORY && item.getLocation() != L2ItemInstance.ItemLocation.PAPERDOLL)
{
player.sendActionFailed();
player.sendPacket(Msg.INAPPROPRIATE_ENCHANT_CONDITIONS);
return true;
}
if (player.getPrivateStoreType() != L2Player.STORE_PRIVATE_NONE)
{
player.sendPacket(new ExPutEnchantTargetItemResult(0, 0, 0));
player.sendPacket(Msg.YOU_CANNOT_PRACTICE_ENCHANTING_WHILE_OPERATING_A_PRIVATE_STORE_OR_PRIVATE_MANUFACTURING_WORKSHOP);
return true;
}
if ((scroll = inventory.getItemByObjectId(scroll.getObjectId())) == null)
{
player.setEnchantScroll(null);
player.sendPacket(new ExPutEnchantTargetItemResult(0, 0, 0));
return true;
}
if (item.getEnchantLevel() >= data.max_enchant)
{
player.sendActionFailed();
player.sendMessage(new CustomMessage("l2p.gameserver.clientpackets.RequestEnchantItem.MaxLevel", player));
return true;
}
if (item.getOwnerId() != player.getObjectId())
{
player.sendPacket(new ExPutEnchantTargetItemResult(0, 0, 0));
return true;
}
Log.add(player.getName() + "|Trying to put enchant|" + item.getItemId() + "|+" + item.getEnchantLevel() + "|" + item.getObjectId(), "enchants");
player.sendPacket(new ExPutEnchantTargetItemResult(1, 0, 0));
return true;
}
}
а в датапак кладем xml-файл с названием enchant_scrolls.xml и примерно с таким содержанием (как обявлять новые комбинации понятно из комментариев в начале):
Код:
<?xml version="1.0" encoding="utf-8"?>
<list>
<!--
Здесь перечислены нестандартные свитки заточек, используемые для заточки определенных предметов, в основном для эвентов.
Параметры, которые можно задавать для свитков:
id - идентификатор свитка.
chance - шанс удачной заточки (по умолчанию равно 66).
action_of_fail - действие с затачиваемым предметом при неудачной заточке: 0 - удалить, 1 - обнулить заточку, 2 - оставить старую заточку (по умолчанию равно 0).
safe_enchant - до какого уровня заточка является безопасной (по умолчанию равно 3).
max_enchant - до скольки максимум можно точить этим свитком (по умолчанию берется стандартный максимум, указанный в конфигурации сервера).
premium_bonus - прибавка к шансу успешной заточки, если у игрока активен премиум аккаунт (по умолчанию равно 0).
item_to_enchant - идентиикатор предмета, который можно заточить этим свитком (можно указывать несколько предметов, перечисляя идентификаторы через запятую).
Внимание! Свитки обязательно должны быть зарегистрированы как свитки заточки в хэндлере data/scripts/items/EnchantScrolls.java.
-->
<!-- Master Yogi's Scroll: Enchant Weapon -->
<scroll id="13540" chance="66" action_of_fail="0" safe_enchant="3" max_enchant="23" premium_bonus="0" item_to_enchant="13539" />
<!-- Olf's T-shirt Enchant Scroll -->
<scroll id="21581" chance="66" action_of_fail="0" safe_enchant="3" max_enchant="9" premium_bonus="0" item_to_enchant="21580" />
<!-- Blessed Olf's T-shirt Enchant Scroll -->
<scroll id="21582" chance="66" action_of_fail="1" safe_enchant="3" max_enchant="9" premium_bonus="0" item_to_enchant="21580" />
<!-- Blessed Olf's T-shirt Enchant Scroll [Event] -->
<scroll id="21707" chance="66" action_of_fail="1" safe_enchant="3" max_enchant="9" premium_bonus="0" item_to_enchant="21706" />
</list>
Код:
GameServer.java:
Добавить в любое удобное место метода GameServer(), где вызываются остальные подобные классы, строку
EnchantScrollData.getInstance();
---------
RequestEnchantItem.java:
Добавить после строк
if (!RequestExTryToPutEnchantSupportItem.checkCatalyst(itemToEnchant, catalyst))
catalyst = null;
строки
if (EnchantScrollData.getInstance().requestEnchantItem(activeChar, inventory, scroll, itemToEnchant))
return;
---------
RequestExTryToPutEnchantTargetItem.java:
Добавить после строк
if (itemToEnchant == null || scroll == null)
{
activeChar.sendPacket(new ExPutEnchantTargetItemResult(0, 0, 0));
return;
}
строки
if (EnchantScrollData.getInstance().requestExTryToPutEnchantTargetItem(activeChar, inventory, scroll, itemToEnchant))
return;
Так же стоит почистить пакеты RequestEnchantItem и RequestExTryToPutEnchantTargetItem от уже ненужных проверок на соответствие вещей на свиток и посох из эвента Master of Enchanting - все равно это будет после всего этого мертвым кодом.
З.Ы. и да, просьба к определенным личностям не тырить шару и не продавать ее потом как свою "собственноручно написанную разработку, которую вы можете купить только у нас" - намек думаю понятно кому адресован