- Хроники
- Master Class
- Исходники
- Присутствуют
- Сборка
- L2jMobius
Ребята, подскажите пожалуйста где искать спистк итемов при получении которых в инвентарь игрока выводится сообщение по центру экрана о том что такойто персонаж получил такой то итем.
Посмотрите видео ниже, чтобы узнать, как установить наш сайт в виде веб-приложения на главном экране.
Примечание: Эта функция может быть недоступна в некоторых браузерах.
Код:Compilation diagnostics ----------------------- WARNING: Unknown Source, Line -1, Column -1 code: compiler.warn.option.obsolete.source message: source value 8 is obsolete and will be removed in a future release WARNING: Unknown Source, Line -1, Column -1 code: compiler.warn.option.obsolete.target message: target value 8 is obsolete and will be removed in a future release WARNING: Unknown Source, Line -1, Column -1 code: compiler.warn.option.obsolete.suppression message: To suppress warnings about obsolete options, use -Xlint:-options. ERROR: data\scripts\handlers\itemhandlers\ExtractableItems.java, Line 361, Column 63 code: compiler.err.cant.resolve.location...
data/limitshop , limishopCraftРебята, подскажите пожалуйста где искать спистк итемов при получении которых в инвентарь игрока выводится сообщение по центру экрана о том что такойто персонаж получил такой то итем.
<product id="3707" category="5">
<ingredient id="94166" enchant="10" count="1" /> <!-- +10 Circlet of Hero (Sealed) -->
<ingredient id="94166" enchant="10" count="1" /> <!-- +10 Circlet of Hero (Sealed) -->
<production id="98205" enchant="10" count="1" chance="100" announce="true" /> <!-- +10 Blessed Circlet of Hero -->
</product>
К сожалению это не то. Попробовал прикрутить атрибут к дропу с сундука, ничего не вышло. Мне нужно чтоб когда открываешь лут сундуки и получаешь некоторые итемы сообщение выводилось по центру экрана у всех игроков как при заточке на скрине.data/limitshop , limishopCraft
в limitshop.xsd есть все атрибуты
XML:<product id="3707" category="5"> <ingredient id="94166" enchant="10" count="1" /> <!-- +10 Circlet of Hero (Sealed) --> <ingredient id="94166" enchant="10" count="1" /> <!-- +10 Circlet of Hero (Sealed) --> <production id="98205" enchant="10" count="1" chance="100" announce="true" /> <!-- +10 Blessed Circlet of Hero --> </product>
org\l2jmobius\gameserver\network\serverpackets\autopeel\ExResultItemAutoPeelК сожалению это не то. Попробовал прикрутить атрибут к дропу с сундука, ничего не вышло. Мне нужно чтоб когда открываешь лут сундуки и получаешь некоторые итемы сообщение выводилось по центру экрана у всех игроков как при заточке на скрине.
Можешь пожалуйста объяснить что и куда нужно добавить чтоб реализовать это? java файл в исходниках я нашел, он ссылается на какой то _itemList. Я так понимаю нужно его ковырять?org\l2jmobius\gameserver\network\serverpackets\autopeel\ExResultItemAutoPeel
Мне это интересно и я пытаюсь разобраться сам. А уровень знаний у всех когда то был как у меня. Ничего выросли же)?Подозреваю что с таким уровнем знаний тебе только один путь, в https://mmo-dev.info/forums/Ищу-исполнителя.56/
Этот функционал уже релизован в сборке, но как я понимаю просто не привязан к id итемов которые нужно анонсить.Тебе надо разбираться с тем где и как вызывается пакет ExItemAnnounce и прикрутить его броадкаст всем игрокам в нужные места в коде.
Но подозреваю что с таким уровнем знаний тебе только один путь, в https://mmo-dev.info/forums/Ищу-исполнителя.56/
// Announce the success.
if ((item.getEnchantLevel() >= (item.isArmor() ? Config.MIN_ARMOR_ENCHANT_ANNOUNCE : Config.MIN_WEAPON_ENCHANT_ANNOUNCE)) //
&& (item.getEnchantLevel() <= (item.isArmor() ? Config.MAX_ARMOR_ENCHANT_ANNOUNCE : Config.MAX_WEAPON_ENCHANT_ANNOUNCE)))
{
final SystemMessage sm = new SystemMessage(SystemMessageId.C1_HAS_ENCHANTED_S3_UP_TO_S2);
sm.addString(player.getName());
sm.addInt(item.getEnchantLevel());
sm.addItemName(item);
player.broadcastPacket(sm);
Broadcast.toAllOnlinePlayers(new ExItemAnnounce(player, item, ExItemAnnounce.ENCHANT));
final Skill skill = CommonSkill.FIREWORK.getSkill();
if (skill != null)
{
player.broadcastPacket(new MagicSkillUse(player, player, skill.getId(), skill.getLevel(), skill.getHitTime(), skill.getReuseDelay()));
}
}
Это наверное сборка хроник Master Class? У меня Shinemaker. К сожалению при создании темы засталяет выбирать хроники, и моих там нет. Эти ближе всего. Ну вот даже тут к примеру удачная заточка брони и оружия выведена параметрами в конфиг. Можно же создать условие что если id итема есть в списке (допустим в тот же конфиг вывести айдишники нужных итемов) то анонсировать получение этого предмета.Извиняюсь, оказывается енчант тут первобытный.
Java:// Announce the success. if ((item.getEnchantLevel() >= (item.isArmor() ? Config.MIN_ARMOR_ENCHANT_ANNOUNCE : Config.MIN_WEAPON_ENCHANT_ANNOUNCE)) // && (item.getEnchantLevel() <= (item.isArmor() ? Config.MAX_ARMOR_ENCHANT_ANNOUNCE : Config.MAX_WEAPON_ENCHANT_ANNOUNCE))) { final SystemMessage sm = new SystemMessage(SystemMessageId.C1_HAS_ENCHANTED_S3_UP_TO_S2); sm.addString(player.getName()); sm.addInt(item.getEnchantLevel()); sm.addItemName(item); player.broadcastPacket(sm); Broadcast.toAllOnlinePlayers(new ExItemAnnounce(player, item, ExItemAnnounce.ENCHANT)); final Skill skill = CommonSkill.FIREWORK.getSkill(); if (skill != null) { player.broadcastPacket(new MagicSkillUse(player, player, skill.getId(), skill.getLevel(), skill.getHitTime(), skill.getReuseDelay())); } }
анонсировать получение предмета... откуда?Это наверное сборка хроник Master Class? У меня Shinemaker. К сожалению при создании темы засталяет выбирать хроники, и моих там нет. Эти ближе всего. Ну вот даже тут к примеру удачная заточка брони и оружия выведена параметрами в конфиг. Можно же создать условие что если id итема есть в списке (допустим в тот же конфиг вывести айдишники нужных итемов) то анонсировать получение этого предмета.
При открытии сундуков с рандомным дропом.анонсировать получение предмета... откуда?
Из заточки? При заточке будет "анонс успешно модификированного предмета"Более конкретнее можно?
Вот так это выглядит на офе. (то что мне нужно)При открытии сундуков с рандомным дропом.
При открытии сундуков с рандомным дропом.
В каждой отдельной xml-ки есть "announce", будь-то /stats/items (извлечение)
ExtractableItems
записать ИД предметов, которые нужно будет "анонсить" и отправлять пакет всем, после любого метода "addItem";Вот так это должно выглядеть в конечном итоге.прикольно. У мобиуса нет "анонса" для лут-боксов.
Я бы это описал бы "Очаровательно".
Ну в таком случае:
- или хардкодом вExtractableItems
записать ИД предметов, которые нужно будет "анонсить" и отправлять пакет всем, после любого метода "addItem";
- или дописывать всем сундукам announce тег, или создать отдельный файл с анонсами итемами (ака ПТС лайк, где стоит ИДшник и чем меньше он - тем больше нужно итемов единоразово получить чтобы был анонс) - и потом опять же в хендлерах проверять список.
Это уже или самому делать, или как описал Гайка(тсу) - в тему "Ищу исполнителя".
я знаю как это должно выглядять.Вот так это должно выглядеть в конечном итоге.
Спасибо большое, может подскажешь к кому можно обратиться по данному вопросу? Или может сам можешь помочь. Не бесплатно конечно.я знаю как это должно выглядять.
В последних сборках, с которыми я работал - это есть.
Мобиуса в руках года 2 не держал - так что даже удивлен что он так тормозит.
В любом случае - ответ у Вас есть.
/*
* Copyright (c) 2013 L2jMobius
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package handlers.itemhandlers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.l2jmobius.Config;
import org.l2jmobius.commons.util.Rnd;
import org.l2jmobius.gameserver.data.xml.ItemData;
import org.l2jmobius.gameserver.handler.IItemHandler;
import org.l2jmobius.gameserver.managers.DailyResetManager;
import org.l2jmobius.gameserver.model.ExtractableProduct;
import org.l2jmobius.gameserver.model.actor.Playable;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.actor.request.AutoPeelRequest;
import org.l2jmobius.gameserver.model.item.EtcItem;
import org.l2jmobius.gameserver.model.item.ItemTemplate;
import org.l2jmobius.gameserver.model.item.enums.ItemProcessType;
import org.l2jmobius.gameserver.model.item.enums.SpecialItemType;
import org.l2jmobius.gameserver.model.item.holders.ItemHolder;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.serverpackets.ExItemAnnounce;
import org.l2jmobius.gameserver.network.serverpackets.ExPCCafePointInfo;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import org.l2jmobius.gameserver.network.serverpackets.autopeel.ExResultItemAutoPeel;
import org.l2jmobius.gameserver.network.serverpackets.autopeel.ExStopItemAutoPeel;
/**
* Extractable Items handler.
* @author HorridoJoho, Mobius
*/
public class ExtractableItems implements IItemHandler
{
@Override
public boolean useItem(Playable playable, Item item, boolean forceUse)
{
if (!playable.isPlayer())
{
playable.sendPacket(SystemMessageId.YOUR_PET_CANNOT_CARRY_THIS_ITEM);
return false;
}
final Player player = playable.asPlayer();
final EtcItem etcitem = (EtcItem) item.getTemplate();
final List<ExtractableProduct> exitems = etcitem.getExtractableItems();
if (exitems == null)
{
LOGGER.info("No extractable data defined for " + etcitem);
return false;
}
if (!player.isInventoryUnder80(false))
{
player.sendPacket(SystemMessageId.NOT_ENOUGH_SPACE_IN_INVENTORY_UNABLE_TO_PROCESS_THIS_REQUEST_UNTIL_YOUR_INVENTORY_S_WEIGHT_IS_LESS_THAN_80_AND_SLOT_COUNT_IS_LESS_THAN_90_OF_CAPACITY);
return false;
}
// destroy item
if (!DailyResetManager.RESET_ITEMS.contains(item.getId()) && !player.destroyItem(ItemProcessType.FEE, item.getObjectId(), 1, player, true))
{
return false;
}
boolean specialReward = false;
final Map<Item, Long> extractedItems = new HashMap<>();
final List<Item> enchantedItems = new ArrayList<>();
if (etcitem.getExtractableCountMin() > 0)
{
while (extractedItems.size() < etcitem.getExtractableCountMin())
{
for (ExtractableProduct expi : exitems)
{
if ((etcitem.getExtractableCountMax() > 0) && (extractedItems.size() == etcitem.getExtractableCountMax()))
{
break;
}
if (Rnd.get(100000) <= expi.getChance())
{
final long min = (long) (expi.getMin() * Config.RATE_EXTRACTABLE);
final long max = (long) (expi.getMax() * Config.RATE_EXTRACTABLE);
long createItemAmount = (max == min) ? min : (Rnd.get((max - min) + 1) + min);
if (createItemAmount == 0)
{
continue;
}
// Do not extract the same item.
boolean alreadyExtracted = false;
for (Item i : extractedItems.keySet())
{
if (i.getTemplate().getId() == expi.getId())
{
alreadyExtracted = true;
break;
}
}
if (alreadyExtracted && (exitems.size() >= etcitem.getExtractableCountMax()))
{
continue;
}
if (expi.getId() == -1) // Prime points
{
player.setPrimePoints(player.getPrimePoints() + (int) createItemAmount);
player.sendMessage("You have obtained " + (createItemAmount / 100) + " Euro!");
specialReward = true;
continue;
}
else if (expi.getId() == SpecialItemType.PC_CAFE_POINTS.getClientId())
{
final int currentPoints = player.getPcCafePoints();
final int upgradePoints = player.getPcCafePoints() + (int) createItemAmount;
player.setPcCafePoints(upgradePoints);
final SystemMessage message = new SystemMessage(SystemMessageId.YOU_HAVE_RECEIVED_S1_POINT_S_AS_A_DAILY_REWARD_FOR_USING_EVA_S_GRACE).addInt((int) createItemAmount);
player.sendPacket(message);
player.sendPacket(new ExPCCafePointInfo(currentPoints, upgradePoints, 1));
specialReward = true;
continue;
}
else if (expi.getId() == SpecialItemType.HONOR_COINS.getClientId())
{
player.setHonorCoins(player.getHonorCoins() + (int) createItemAmount);
player.sendMessage("You have obtained " + (createItemAmount) + " Honor Coin.");
specialReward = true;
continue;
}
final ItemTemplate template = ItemData.getInstance().getTemplate(expi.getId());
if (template == null)
{
LOGGER.warning("ExtractableItems: Could not find " + item + " product template with id " + expi.getId() + "!");
continue;
}
if (template.isStackable() || (createItemAmount == 1))
{
final Item newItem = player.addItem(ItemProcessType.REWARD, expi.getId(), createItemAmount, player, false);
if (expi.getMaxEnchant() > 0)
{
newItem.setEnchantLevel(Rnd.get(expi.getMinEnchant(), expi.getMaxEnchant()));
enchantedItems.add(newItem);
}
// Send item announcement if configured
if (expi.isAnnounce())
{
player.broadcastPacket(new ExItemAnnounce(player, newItem, ExItemAnnounce.CONTAINER, item.getId()));
}
addItem(extractedItems, newItem, createItemAmount);
}
else
{
while (createItemAmount > 0)
{
final Item newItem = player.addItem(ItemProcessType.REWARD, expi.getId(), 1, player, false);
if (expi.getMaxEnchant() > 0)
{
newItem.setEnchantLevel(Rnd.get(expi.getMinEnchant(), expi.getMaxEnchant()));
enchantedItems.add(newItem);
}
// Send item announcement if configured
if (expi.isAnnounce())
{
player.broadcastPacket(new ExItemAnnounce(player, newItem, ExItemAnnounce.CONTAINER, item.getId()));
}
addItem(extractedItems, newItem, 1);
createItemAmount--;
}
}
}
}
}
}
else
{
for (ExtractableProduct expi : exitems)
{
if ((etcitem.getExtractableCountMax() > 0) && (extractedItems.size() == etcitem.getExtractableCountMax()))
{
break;
}
if (Rnd.get(100000) <= expi.getChance())
{
final long min = (long) (expi.getMin() * Config.RATE_EXTRACTABLE);
final long max = (long) (expi.getMax() * Config.RATE_EXTRACTABLE);
long createItemAmount = (max == min) ? min : (Rnd.get((max - min) + 1) + min);
if (createItemAmount == 0)
{
continue;
}
if (expi.getId() == -1) // Prime points
{
player.setPrimePoints(player.getPrimePoints() + (int) createItemAmount);
player.sendMessage("You have obtained " + (createItemAmount / 100) + " Euro!");
specialReward = true;
continue;
}
else if (expi.getId() == SpecialItemType.PC_CAFE_POINTS.getClientId())
{
final int currentPoints = player.getPcCafePoints();
final int upgradePoints = player.getPcCafePoints() + (int) createItemAmount;
player.setPcCafePoints(upgradePoints);
final SystemMessage message = new SystemMessage(SystemMessageId.YOU_HAVE_RECEIVED_S1_POINT_S_AS_A_DAILY_REWARD_FOR_USING_EVA_S_GRACE).addInt((int) createItemAmount);
player.sendPacket(message);
player.sendPacket(new ExPCCafePointInfo(currentPoints, upgradePoints, 1));
specialReward = true;
continue;
}
else if (expi.getId() == SpecialItemType.HONOR_COINS.getClientId())
{
player.setHonorCoins(player.getHonorCoins() + (int) createItemAmount);
player.sendMessage("You have obtained " + (createItemAmount) + " Honor Coin.");
specialReward = true;
continue;
}
final ItemTemplate template = ItemData.getInstance().getTemplate(expi.getId());
if (template == null)
{
LOGGER.warning("ExtractableItems: Could not find " + item + " product template with id " + expi.getId() + "!");
continue;
}
if (template.isStackable() || (createItemAmount == 1))
{
final Item newItem = player.addItem(ItemProcessType.REWARD, expi.getId(), createItemAmount, player, false);
if (expi.getMaxEnchant() > 0)
{
newItem.setEnchantLevel(Rnd.get(expi.getMinEnchant(), expi.getMaxEnchant()));
enchantedItems.add(newItem);
}
// Send item announcement if configured
if (expi.isAnnounce())
{
player.broadcastPacket(new ExItemAnnounce(player, newItem, ExItemAnnounce.CONTAINER, item.getId()));
}
addItem(extractedItems, newItem, createItemAmount);
}
else
{
while (createItemAmount > 0)
{
final Item newItem = player.addItem(ItemProcessType.REWARD, expi.getId(), 1, player, false);
if (expi.getMaxEnchant() > 0)
{
newItem.setEnchantLevel(Rnd.get(expi.getMinEnchant(), expi.getMaxEnchant()));
enchantedItems.add(newItem);
}
// Send item announcement if configured
if (expi.isAnnounce())
{
player.broadcastPacket(new ExItemAnnounce(player, newItem, ExItemAnnounce.CONTAINER, item.getId()));
}
addItem(extractedItems, newItem, 1);
createItemAmount--;
}
}
}
}
}
if (extractedItems.isEmpty() && !specialReward)
{
player.sendPacket(SystemMessageId.FAILED_TO_CHANGE_THE_ITEM);
}
if (!enchantedItems.isEmpty())
{
final InventoryUpdate playerIU = new InventoryUpdate();
for (Item i : enchantedItems)
{
playerIU.addModifiedItem(i);
}
player.sendInventoryUpdate(playerIU);
}
for (Entry<Item, Long> entry : extractedItems.entrySet())
{
sendMessage(player, entry.getKey(), entry.getValue());
}
final AutoPeelRequest request = player.getRequest(AutoPeelRequest.class);
if (request != null)
{
if (request.isProcessing())
{
request.setProcessing(false);
final List<ItemHolder> rewards = new LinkedList<>();
for (Entry<Item, Long> entry : extractedItems.entrySet())
{
rewards.add(new ItemHolder(entry.getKey().getId(), entry.getValue()));
}
player.sendPacket(new ExResultItemAutoPeel(true, request.getTotalPeelCount(), request.getRemainingPeelCount() - 1, rewards));
}
else
{
player.sendPacket(new ExStopItemAutoPeel(false));
}
}
else // Fixes last auto peel not shown. No effect if auto peel window is closed.
{
final List<ItemHolder> rewards = new LinkedList<>();
for (Entry<Item, Long> entry : extractedItems.entrySet())
{
rewards.add(new ItemHolder(entry.getKey().getId(), entry.getValue()));
}
player.sendPacket(new ExResultItemAutoPeel(true, 0, 0, rewards));
}
return true;
}
private void addItem(Map<Item, Long> extractedItems, Item newItem, long count)
{
if (extractedItems.containsKey(newItem))
{
extractedItems.put(newItem, extractedItems.get(newItem) + count);
}
else
{
extractedItems.put(newItem, count);
}
}
private void sendMessage(Player player, Item item, long count)
{
final SystemMessage sm;
if (count > 1)
{
sm = new SystemMessage(SystemMessageId.YOU_HAVE_OBTAINED_S1_X_S2);
sm.addItemName(item);
sm.addLong(count);
}
else if (item.getEnchantLevel() > 0)
{
sm = new SystemMessage(SystemMessageId.YOU_HAVE_OBTAINED_S1_S2);
sm.addInt(item.getEnchantLevel());
sm.addItemName(item);
}
else
{
sm = new SystemMessage(SystemMessageId.YOU_HAVE_OBTAINED_S1);
sm.addItemName(item);
}
player.sendPacket(sm);
}
}
}
* 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;
/**
* @author JIV
*/
public class ExtractableProduct
{
private final int _id;
private final long _min;
private final long _max;
private final int _chance;
private final int _minEnchant;
private final int _maxEnchant;
private final boolean _announce;
/**
* Create Extractable product
@@ -38,13 +39,29 @@
* @param maxEnchant item max enchant
*/
public ExtractableProduct(int id, long min, long max, double chance, int minEnchant, int maxEnchant)
{
this(id, min, max, chance, minEnchant, maxEnchant, false);
}
/**
* Create Extractable product
* @param id create item id
* @param min item count max
* @param max item count min
* @param chance chance for creating
* @param minEnchant item min enchant
* @param maxEnchant item max enchant
* @param announce announce item
*/
public ExtractableProduct(int id, long min, long max, double chance, int minEnchant, int maxEnchant, boolean announce)
{
_id = id;
_min = min;
_max = max;
_chance = (int) (chance * 1000);
_minEnchant = minEnchant;
_maxEnchant = maxEnchant;
_announce = announce;
}
public int getId()
@@ -76,4 +93,9 @@
{
return _maxEnchant;
}
public boolean isAnnounce()
{
return _announce;
}
}
/*
* 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.util;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.gameserver.model.ExtractableProduct;
import org.l2jmobius.gameserver.model.StatSet;
import org.l2jmobius.gameserver.model.conditions.Condition;
import org.l2jmobius.gameserver.model.item.ItemTemplate;
import org.l2jmobius.gameserver.model.item.enums.ItemSkillType;
import org.l2jmobius.gameserver.model.item.holders.ItemSkillHolder;
import org.l2jmobius.gameserver.model.stats.Stat;
import org.l2jmobius.gameserver.model.stats.functions.FuncTemplate;
/**
* @author mkizub, JIV
*/
public class DocumentItem extends DocumentBase implements IXmlReader
{
private static final Logger LOGGER = Logger.getLogger(DocumentItem.class.getName());
private DocumentItemDataHolder _currentItem = null;
private final List<ItemTemplate> _itemsInFile = new ArrayList<>();
private class DocumentItemDataHolder
{
public DocumentItemDataHolder()
{
}
int id;
String type;
StatSet set;
int currentLevel;
ItemTemplate item;
}
public DocumentItem(File file)
{
super(file);
}
@Override
protected StatSet getStatSet()
{
return _currentItem.set;
}
@Override
protected String getTableValue(String name)
{
return _tables.get(name)[_currentItem.currentLevel];
}
@Override
protected String getTableValue(String name, int idx)
{
return _tables.get(name)[idx - 1];
}
@Override
protected void parseDocument(Document document)
{
for (Node n = document.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("item".equalsIgnoreCase(d.getNodeName()))
{
try
{
_currentItem = new DocumentItemDataHolder();
parseItem(d);
_itemsInFile.add(_currentItem.item);
resetTable();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Cannot create item " + _currentItem.id, e);
}
}
}
}
}
}
private void parseItem(Node node) throws InvocationTargetException
{
Node n = node;
final int itemId = Integer.parseInt(n.getAttributes().getNamedItem("id").getNodeValue());
final String className = n.getAttributes().getNamedItem("type").getNodeValue();
final String itemName = n.getAttributes().getNamedItem("name").getNodeValue();
final String additionalName = n.getAttributes().getNamedItem("additionalName") != null ? n.getAttributes().getNamedItem("additionalName").getNodeValue() : null;
_currentItem.id = itemId;
_currentItem.type = className;
_currentItem.set = new StatSet();
_currentItem.set.set("item_id", itemId);
_currentItem.set.set("name", itemName);
_currentItem.set.set("additionalName", additionalName);
final Node first = n.getFirstChild();
for (n = first; n != null; n = n.getNextSibling())
{
if ("table".equalsIgnoreCase(n.getNodeName()))
{
if (_currentItem.item != null)
{
throw new IllegalStateException("Item created but table node found! Item " + itemId);
}
parseTable(n);
}
else if ("set".equalsIgnoreCase(n.getNodeName()))
{
if (_currentItem.item != null)
{
throw new IllegalStateException("Item created but set node found! Item " + itemId);
}
parseBeanSet(n, _currentItem.set, 1);
}
else if ("stats".equalsIgnoreCase(n.getNodeName()))
{
makeItem();
for (Node b = n.getFirstChild(); b != null; b = b.getNextSibling())
{
if ("stat".equalsIgnoreCase(b.getNodeName()))
{
final Stat type = Stat.valueOfXml(b.getAttributes().getNamedItem("type").getNodeValue());
final double value = Double.parseDouble(b.getTextContent());
_currentItem.item.addFunctionTemplate(new FuncTemplate(null, null, "add", 0x00, type, value));
}
}
}
else if ("skills".equalsIgnoreCase(n.getNodeName()))
{
makeItem();
for (Node b = n.getFirstChild(); b != null; b = b.getNextSibling())
{
if ("skill".equalsIgnoreCase(b.getNodeName()))
{
final int id = parseInteger(b.getAttributes(), "id");
final int level = parseInteger(b.getAttributes(), "level");
final int subLevel = parseInteger(b.getAttributes(), "subLevel", 0);
final ItemSkillType type = parseEnum(b.getAttributes(), ItemSkillType.class, "type", ItemSkillType.NORMAL);
final int chance = parseInteger(b.getAttributes(), "type_chance", 100);
final int value = parseInteger(b.getAttributes(), "type_value", 0);
final int gearScore = parseInteger(b.getAttributes(), "gearScore", 0);
if (type == ItemSkillType.ON_ENCHANT)
{
final int enchantLimit = _currentItem.item.getEnchantLimit();
if ((enchantLimit > 0) && (value > enchantLimit))
{
LOGGER.warning(getClass().getSimpleName() + ": Item " + itemId + " has ON_ENCHANT value greater than it's enchant limit.");
}
}
_currentItem.item.addSkill(new ItemSkillHolder(id, level, subLevel, type, chance, value, gearScore));
}
}
}
else if ("capsuled_items".equalsIgnoreCase(n.getNodeName()))
{
makeItem();
for (Node b = n.getFirstChild(); b != null; b = b.getNextSibling())
{
if ("item".equals(b.getNodeName()))
{
final int id = parseInteger(b.getAttributes(), "id");
final long min = parseLong(b.getAttributes(), "min");
final long max = parseLong(b.getAttributes(), "max");
final double chance = parseDouble(b.getAttributes(), "chance");
final int minEnchant = parseInteger(b.getAttributes(), "minEnchant", 0);
final int maxEnchant = parseInteger(b.getAttributes(), "maxEnchant", 0);
_currentItem.item.addCapsuledItem(new ExtractableProduct(id, min, max, chance, minEnchant, maxEnchant));
final boolean announce = parseBoolean(b.getAttributes(), "announce", false);
_currentItem.item.addCapsuledItem(new ExtractableProduct(id, min, max, chance, minEnchant, maxEnchant, announce));
}
}
}
else if ("cond".equalsIgnoreCase(n.getNodeName()))
{
makeItem();
final Condition condition = parseCondition(n.getFirstChild(), _currentItem.item);
final Node msg = n.getAttributes().getNamedItem("msg");
final Node msgId = n.getAttributes().getNamedItem("msgId");
if ((condition != null) && (msg != null))
{
condition.setMessage(msg.getNodeValue());
}
else if ((condition != null) && (msgId != null))
{
condition.setMessageId(Integer.decode(getValue(msgId.getNodeValue(), null)));
final Node addName = n.getAttributes().getNamedItem("addName");
if ((addName != null) && (Integer.decode(getValue(msgId.getNodeValue(), null)) > 0))
{
condition.addName();
}
}
_currentItem.item.attachCondition(condition);
}
}
// bah! in this point item doesn't have to be still created
makeItem();
}
private void makeItem() throws InvocationTargetException
{
// If item exists just reload the data.
if (_currentItem.item != null)
{
_currentItem.item.set(_currentItem.set);
return;
}
try
{
final Constructor<?> itemClass = Class.forName("org.l2jmobius.gameserver.model.item." + _currentItem.type).getConstructor(StatSet.class);
_currentItem.item = (ItemTemplate) itemClass.newInstance(_currentItem.set);
}
catch (Exception e)
{
throw new InvocationTargetException(e);
}
}
public List<ItemTemplate> getItemList()
{
return _itemsInFile;
}
@Override
public void load()
{
}
@Override
public void parseDocument(Document document, File file)
{
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="item">
<xs:complexType>
<xs:sequence>
<xs:choice maxOccurs="unbounded">
<xs:element maxOccurs="unbounded" name="set">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="val" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element name="skills">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="skill">
<xs:complexType>
<xs:attribute name="id" type="xs:int" use="required" />
<xs:attribute name="level" type="xs:unsignedByte" use="required" />
<xs:attribute name="subLevel" type="xs:unsignedShort" use="optional" />
<xs:attribute name="type" type="xs:string" use="optional" />
<xs:attribute name="type_value" type="xs:unsignedByte" use="optional" />
<xs:attribute name="type_chance" type="xs:unsignedByte" use="optional" />
<xs:attribute name="gearScore" type="xs:int" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="stats">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="stat">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:decimal">
<xs:attribute name="type" type="xs:string" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="cond">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="target">
<xs:complexType>
<xs:attribute name="levelRange" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="and">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="player">
<xs:complexType>
<xs:attribute name="castle" type="xs:byte" use="optional" />
<xs:attribute name="pledgeClass" type="xs:byte" use="optional" />
<xs:attribute name="sex" type="xs:unsignedByte" use="optional" />
<xs:attribute name="class_id_restriction" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="player">
<xs:complexType>
<xs:attribute name="flyMounted" type="xs:boolean" use="optional" />
<xs:attribute name="isHero" type="xs:boolean" use="optional" />
<xs:attribute name="sex" type="xs:unsignedByte" use="optional" />
<xs:attribute name="level" type="xs:unsignedByte" use="optional" />
<xs:attribute name="chaotic" type="xs:boolean" use="optional" />
<xs:attribute name="levelRange" type="xs:string" use="optional" />
<xs:attribute name="insideZoneId" type="xs:string" use="optional" />
<xs:attribute name="class_id_restriction" type="xs:string" use="optional" />
<xs:attribute name="categoryType" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" name="not">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="player">
<xs:complexType>
<xs:attribute name="active_effect_id" type="xs:unsignedShort" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="addName" type="xs:unsignedByte" use="optional" />
<xs:attribute name="msgId" type="xs:unsignedShort" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="capsuled_items">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element maxOccurs="unbounded" name="item">
<xs:complexType>
<xs:attribute name="id" type="xs:integer" use="required" />
<xs:attribute name="min" type="xs:unsignedLong" use="required" />
<xs:attribute name="max" type="xs:unsignedLong" use="required" />
<xs:attribute name="chance" type="xs:decimal" use="required" />
<xs:attribute name="minEnchant" type="xs:unsignedByte" use="optional" />
<xs:attribute name="maxEnchant" type="xs:unsignedByte" use="optional" />
<xs:attribute name="announce" type="xs:boolean" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:sequence>
<xs:attribute name="id" type="xs:unsignedInt" use="required" />
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="type" type="xs:string" use="required" />
<xs:attribute name="additionalName" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<item id="96821" name="Kit: Pack of Seals (Time-limited)" additionalName="Sealed" type="EtcItem">
<!-- Double-click to obtain the following. -->
<set name="icon" val="icon.present_of_destination_event" />
<set name="default_action" val="PEEL" />
<set name="immediate_effect" val="true" />
<set name="material" val="FISH" />
<set name="is_tradable" val="false" />
<set name="is_dropable" val="false" />
<set name="is_sellable" val="false" />
<set name="is_stackable" val="true" />
<set name="handler" val="ExtractableItems" />
<set name="extractableCountMin" val="1" />
<set name="extractableCountMax" val="1" />
<capsuled_items>
<item id="96820" min="100" max="100" chance="47.5" announce="true"/> <!-- Pack of Seals (Time-limited) - Sealed -->
<item id="96729" min="100" max="100" chance="47.5" announce="true"/> <!-- Einhasad's Protection - Sealed -->
<item id="92314" min="1" max="1" chance="2.040816" announce="false"/> <!-- Giran Seal -->
</capsuled_items>
</item>
--- a/java/org/l2jmobius/gameserver/network/serverpackets/ExItemAnnounce.java
+++ b/java/org/l2jmobius/gameserver/network/serverpackets/ExItemAnnounce.java
@@ -42,12 +42,23 @@ public class ExItemAnnounce extends ServerPacket
private final Item _item;
private final int _type;
private final String _announceName;
+ private final int _sourceId;
public ExItemAnnounce(Player player, Item item, int type)
{
+ this(player, item, type, 0);
+ }
+
+ public ExItemAnnounce(Player player, Item item, int type, int sourceId)
+ {
_item = item;
_type = type;
+ _sourceId = sourceId;
if (player.getClientSettings().isAnnounceEnabled())
{
_announceName = player.getName();
@@ -82,6 +93,6 @@ public class ExItemAnnounce extends ServerPacket
buffer.writeSizedString(_announceName); // name of player
buffer.writeInt(_item.getId()); // item id
buffer.writeByte(_item.getEnchantLevel()); // enchant level
- buffer.writeInt(0); // chest item id
+ buffer.writeInt(_sourceId); // chest item id
}
}
--- a/java/org/l2jmobius/gameserver/network/serverpackets/ExItemAnnounce.java
+++ b/java/org/l2jmobius/gameserver/network/serverpackets/ExItemAnnounce.java
@@ -42,12 +42,23 @@ public class ExItemAnnounce extends ServerPacket
private final Item _item;
private final int _type;
private final String _announceName;
+ private final int _sourceId;
public ExItemAnnounce(Player player, Item item, int type)
{
+ this(player, item, type, 0);
+ }
+
+ public ExItemAnnounce(Player player, Item item, int type, int sourceId)
+ {
_item = item;
_type = type;
+ _sourceId = sourceId;
if (player.getClientSettings().isAnnounceEnabled())
{
_announceName = player.getName();
@@ -82,6 +93,6 @@ public class ExItemAnnounce extends ServerPacket
buffer.writeSizedString(_announceName); // name of player
buffer.writeInt(_item.getId()); // item id
buffer.writeByte(_item.getEnchantLevel()); // enchant level
- buffer.writeInt(0); // chest item id
+ buffer.writeInt(_sourceId); // chest item id
}
}