Перейти к содержанию
Авторизация  
Gaikotsu

[Share] Beauty Shop

Рекомендуемые сообщения

Думаю все в курсе, что в Lindvior ввели Beauty Shop (салон красоты), предназначенный для изменения внешнего вида персонажей (прически, цвета волос, лица).

 

Ну и собственно в данном руководстве я хочу более-менее подробно описать, как реализовать данное дело в сервере, в частности на сервере основанном на оверах.

 

Итак, поехали:

 

Первым делом создадим 3 новых поля в таблице characters, аналоги полей face, hairStyle и hairColor - назовем их к примеру newFace, newHairStyle и newHairColor. Объяснять как читать и писать в эти поля, а так же как добавить новые переменные и геттеры/сеттеры для них в класс Player я не буду - это самые основы знания Java, не знать такое просто грешно.

 

Может сразу возникнуть вполне закономерный вопрос - а почему бы не использовать существующие поля для хранения информации о внешности? Ответ прост - в некоторых ситуациях нам потребуется знать и то, каким была внешность до посещения салона красоты, к примеру для функции отмены изменений в том же самом салоне, или же для фестиваля хаоса - новые прически на фестивале не отображаются (правда насчет этого информация неподтвержденная, но так написано в патчноутах).

 

Далее озаботимся хранилищем данных о допустимых прическах и т.д., а так же загрузкой этих данных при запуске сервера.

 

Хранить данные мы будем в xml-файле следующей структуры:

 

<?xml version="1.0" encoding="utf-8"?>
<!ELEMENT list (config|set)*>

<!ELEMENT config (#PCDATA)*>
<!ATTLIST config
   coin_item_id CDATA #REQUIRED
   def_reset_price CDATA #REQUIRED>

<!ELEMENT set (hair|face)*>
<!ATTLIST set
   id CDATA #REQUIRED>

<!ELEMENT hair (color)*>
<!ATTLIST hair
   id CDATA #REQUIRED
   adena CDATA #REQUIRED
   coins CDATA #REQUIRED
   reset_price CDATA #IMPLIED>

<!ELEMENT color (#PCDATA)>
<!ATTLIST color
   id CDATA #REQUIRED
   adena CDATA #REQUIRED
   coins CDATA #REQUIRED>

<!ELEMENT face (#PCDATA)>
<!ATTLIST face
   id CDATA #REQUIRED
   adena CDATA #REQUIRED
   coins CDATA #REQUIRED
   reset_price CDATA #IMPLIED>

 

И для примера фрагмент xml с данными

 

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE list SYSTEM "beauty_shop.dtd">
<list>
   <config coin_item_id="36308" def_reset_price="1000000" />
   <!-- Human Male Fighter -->
   <set id="0">
       <!-- Прически -->
       <hair id="10001" adena="15000000" coins="0" />    <!-- Настоящий мачо A -->
       <hair id="10002" adena="15000000" coins="0" />    <!-- Прекрасный юноша A -->
       <hair id="10003" adena="0" coins="4">    <!-- Пират -->
           <color id="101" adena="3000000" coins="0" />    <!-- Рекомендация дизайнера -->
           <color id="102" adena="0" coins="1" />    <!-- Светло-кобальтовое небо -->
           <color id="103" adena="0" coins="1" />    <!-- Лиловый виноград -->
           <color id="104" adena="0" coins="1" />    <!-- Розовый карандаш -->
           <color id="105" adena="0" coins="1" />    <!-- Черная бездна -->
           <color id="106" adena="0" coins="1" />    <!-- Изумрудное украшение -->
           <color id="107" adena="0" coins="1" />    <!-- Желтая бабочка -->
           <color id="108" adena="0" coins="1" />    <!-- Вечнозеленый -->
           <color id="109" adena="0" coins="1" />    <!-- Волшебная метель -->
           <color id="110" adena="0" coins="1" />    <!-- Молчание серого ветра -->
       </hair>
       <hair id="10004" adena="0" coins="4">    <!-- Настоящий смельчак -->
           <color id="101" adena="3000000" coins="0" />    <!-- Рекомендация дизайнера -->
           <color id="102" adena="0" coins="1" />    <!-- Светло-кобальтовое небо -->
           <color id="103" adena="0" coins="1" />    <!-- Лиловый виноград -->
           <color id="104" adena="0" coins="1" />    <!-- Розовый карандаш -->
           <color id="105" adena="0" coins="1" />    <!-- Черная бездна -->
           <color id="106" adena="0" coins="1" />    <!-- Изумрудное украшение -->
           <color id="107" adena="0" coins="1" />    <!-- Желтая бабочка -->
           <color id="108" adena="0" coins="1" />    <!-- Вечнозеленый -->
           <color id="109" adena="0" coins="1" />    <!-- Волшебная метель -->
           <color id="110" adena="0" coins="1" />    <!-- Молчание серого ветра -->
       </hair>
       <hair id="10005" adena="15000000" coins="0" />    <!-- Потому что она - моя женщина A -->
       <hair id="10006" adena="15000000" coins="0" />    <!-- Честь джентльмена A -->
       <hair id="10007" adena="0" coins="3" />    <!-- Настоящий мачо B -->
       <hair id="10008" adena="0" coins="3" />    <!-- Прекрасный юноша B -->
       <hair id="10009" adena="0" coins="3" />    <!-- Потому что она - моя женщина B -->
       <hair id="10010" adena="0" coins="3" />    <!-- Честь джентльмена B -->
       <!-- Лица -->
       <face id="20001" adena="2000000" coins="0" reset_price="500000" />    <!-- Стиль A -->
       <face id="20002" adena="2000000" coins="0" reset_price="500000" />    <!-- Стиль B -->
       <face id="20003" adena="2000000" coins="0" reset_price="500000" />    <!-- Стиль C -->
       <face id="20004" adena="0" coins="2" />    <!-- Стиль Орена -->
       <face id="20005" adena="0" coins="2" />    <!-- Стиль Годдарда -->
   </set>
   <!-- Human Female Fighter -->
   <set id="1">
       <!-- Прически -->
       <hair id="10001" adena="15000000" coins="0" />    <!-- Холодная городская девушка A -->
       <hair id="10002" adena="15000000" coins="0" />    <!-- Грибочек A -->
       <hair id="10003" adena="0" coins="4">    <!-- Пират -->
           <color id="101" adena="3000000" coins="0" />    <!-- Рекомендация дизайнера -->
           <color id="102" adena="0" coins="1" />    <!-- Светло-кобальтовое небо -->
           <color id="103" adena="0" coins="1" />    <!-- Лиловый виноград -->
           <color id="104" adena="0" coins="1" />    <!-- Розовый карандаш -->
           <color id="105" adena="0" coins="1" />    <!-- Черная бездна -->
           <color id="106" adena="0" coins="1" />    <!-- Изумрудное украшение -->
           <color id="107" adena="0" coins="1" />    <!-- Желтая бабочка -->
           <color id="108" adena="0" coins="1" />    <!-- Вечнозеленый -->
           <color id="109" adena="0" coins="1" />    <!-- Волшебная метель -->
           <color id="110" adena="0" coins="1" />    <!-- Молчание серого ветра -->
       </hair>
       <hair id="10004" adena="0" coins="4">    <!-- Конский хвост -->
           <color id="101" adena="3000000" coins="0" />    <!-- Рекомендация дизайнера -->
           <color id="102" adena="0" coins="1" />    <!-- Светло-кобальтовое небо -->
           <color id="103" adena="0" coins="1" />    <!-- Лиловый виноград -->
           <color id="104" adena="0" coins="1" />    <!-- Розовый карандаш -->
           <color id="105" adena="0" coins="1" />    <!-- Черная бездна -->
           <color id="106" adena="0" coins="1" />    <!-- Изумрудное украшение -->
           <color id="107" adena="0" coins="1" />    <!-- Желтая бабочка -->
           <color id="108" adena="0" coins="1" />    <!-- Вечнозеленый -->
           <color id="109" adena="0" coins="1" />    <!-- Волшебная метель -->
           <color id="110" adena="0" coins="1" />    <!-- Молчание серого ветра -->
       </hair>
       <hair id="10005" adena="15000000" coins="0" />    <!-- Харизматичная амазонка A -->
       <hair id="10006" adena="15000000" coins="0" />    <!-- Унесенная ветром A -->
       <hair id="10007" adena="0" coins="3" />    <!-- Холодная городская девушка B -->
       <hair id="10008" adena="0" coins="3" />    <!-- Грибочек B -->
       <hair id="10009" adena="0" coins="3" />    <!-- Харизматичная амазонка B -->
       <hair id="10010" adena="0" coins="3" />    <!-- Унесенная ветром B -->
       <!-- Лица -->
       <face id="20001" adena="2000000" coins="0" reset_price="500000" />    <!-- Стиль A -->
       <face id="20002" adena="2000000" coins="0" reset_price="500000" />    <!-- Стиль B -->
       <face id="20003" adena="2000000" coins="0" reset_price="500000" />    <!-- Стиль C -->
       <face id="20004" adena="0" coins="2" />    <!-- Стиль Орена -->
       <face id="20005" adena="0" coins="2" />    <!-- Стиль Годдарда -->
   </set>

   ...

</list>

 

 

Внимательные могут сразу же заметить избыточность данных в файле - для каждой расы/пола в общем-то данные одни и те же. Я это знаю, просто обычно предпочитаю реализовывать многое с учетом того, что может быть сейчас и все одинаково для любой расы/пола, но кто их корейцев знает - могут и изменить в будущем эту ситуацию. Так что в принципе если вам такая избыточность не нужна - это легко все дорабатывается до одного единственного набора данных для любой расы/пола. Опять же это делать вам самим, тем более что это легко - ломать не строить.

 

Далее добавляем в ядро сервера парсер этих данных и хранилище для них.

 

Парсер:

 

package l2p.gameserver.data.xml.parser;

import l2p.commons.data.xml.AbstractFileParser;
import l2p.gameserver.Config;
import l2p.gameserver.data.xml.holder.BeautyShopHolder;
import l2p.gameserver.model.beautyshop.BeautyShopFace;
import l2p.gameserver.model.beautyshop.BeautyShopSet;
import l2p.gameserver.model.beautyshop.BeautyShopHairColor;
import l2p.gameserver.model.beautyshop.BeautyShopHairStyle;
import l2p.gameserver.utils.Util;

import org.dom4j.Element;

import gnu.trove.map.hash.TIntObjectHashMap;

import java.io.File;
import java.util.Iterator;

public final class BeautyShopParser extends AbstractFileParser<BeautyShopHolder>
{
   private static final BeautyShopParser _instance = new BeautyShopParser();

   public static BeautyShopParser getInstance()
   {
       return _instance;
   }

   private BeautyShopParser()
   {
       super(BeautyShopHolder.getInstance());
   }

   @Override
   public File getXMLFile()
   {
       return new File(Config.DATAPACK_ROOT, "data/beauty_shop.xml");
   }

   @Override
   public String getDTDFileName()
   {
       return "beauty_shop.dtd";
   }

   @Override
   protected void readData(Element rootElement) throws Exception
   {
       long defResetPrice = 0L;

       for (Iterator iterator = rootElement.elementIterator("config"); iterator.hasNext(); )
       {
           Element element = (Element) iterator.next();
           Config.BS_COIN_ITEM_ID = Util.parseValue(element.attributeValue("coin_item_id"), 36308);
           defResetPrice = Util.parseValue(element.attributeValue("def_reset_price"), 1000000L);
       }

       for (Iterator iterator = rootElement.elementIterator("set"); iterator.hasNext(); )
       {
           Element element = (Element) iterator.next();
           int setId = Util.parseValue(element.attributeValue("id"), 0);

           TIntObjectHashMap<BeautyShopHairStyle> hairStyles = new TIntObjectHashMap<BeautyShopHairStyle>();
           TIntObjectHashMap<BeautyShopFace> faces = new TIntObjectHashMap<BeautyShopFace>();

           for (Iterator<Element> subIterator = element.elementIterator("hair"); subIterator.hasNext(); )
           {
               Element subElement = subIterator.next();
               int id = Util.parseValue(subElement.attributeValue("id"), 0);
               long adena = Util.parseValue(subElement.attributeValue("adena"), 0L);
               long coins = Util.parseValue(subElement.attributeValue("coins"), 0L);
               long resetPrice = Util.parseValue(subElement.attributeValue("reset_price"), defResetPrice);
               TIntObjectHashMap<BeautyShopHairColor> colors = new TIntObjectHashMap<BeautyShopHairColor>();

               for (Iterator<Element> colorIterator = subElement.elementIterator("color"); colorIterator.hasNext(); )
               {
                   Element colorElement = colorIterator.next();
                   int cId = Util.parseValue(colorElement.attributeValue("id"), 0);
                   long cAdena = Util.parseValue(colorElement.attributeValue("adena"), 0L);
                   long cCoins = Util.parseValue(colorElement.attributeValue("coins"), 0L);
                   colors.put(cId, new BeautyShopHairColor(cId, cAdena, cCoins));
               }

               if (colors.isEmpty())
                   colors.put(101, new BeautyShopHairColor(101, 0, 0));

               hairStyles.put(id, new BeautyShopHairStyle(id, adena, coins, resetPrice, colors));
           }

           for (Iterator<Element> subIterator = element.elementIterator("face"); subIterator.hasNext(); )
           {
               Element subElement = subIterator.next();
               int id = Util.parseValue(subElement.attributeValue("id"), 0);
               long adena = Util.parseValue(subElement.attributeValue("adena"), 0L);
               long coins = Util.parseValue(subElement.attributeValue("coins"), 0L);
               long resetPrice = Util.parseValue(subElement.attributeValue("reset_price"), defResetPrice);
               faces.put(id, new BeautyShopFace(id, adena, coins, resetPrice));
           }

           getHolder().addSet(new BeautyShopSet(setId, hairStyles, faces));
       }
   }
}

 

 

Хранилище:

 

package l2p.gameserver.data.xml.holder;

import gnu.trove.map.hash.TIntObjectHashMap;
import l2p.commons.data.xml.AbstractHolder;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.base.Race;
import l2p.gameserver.model.base.Sex;
import l2p.gameserver.model.beautyshop.BeautyShopSet;

public final class BeautyShopHolder extends AbstractHolder
{
   private static final BeautyShopHolder _instance = new BeautyShopHolder();
   private static final TIntObjectHashMap<BeautyShopSet> _sets = new TIntObjectHashMap<BeautyShopSet>();

   public static BeautyShopHolder getInstance()
   {
       return _instance;
   }

   public void addSet(BeautyShopSet set)
   {
       if (_sets.containsKey(set.getId()))
           warn("Duplicate set declaration, set id - " + set.getId());

       _sets.put(set.getId(), set);
   }

   public BeautyShopSet getSet(int id)
   {
       return _sets.get(id);
   }

   public BeautyShopSet getSet(Player player)
   {
       int id = -1;

       if (player.getRace() == Race.HUMAN)
       {
           if (!player.getClassId().isMage())
               id = player.getSex() == Sex.MALE ? 0 : 1;
           else
               id = player.getSex() == Sex.MALE ? 8 : 9;
       }
       else if (player.getRace() == Race.DARK_ELF)
           id = player.getSex() == Sex.MALE ? 2 : 3;
       else if (player.getRace() == Race.DWARF)
           id = player.getSex() == Sex.MALE ? 4 : 5;
       else if (player.getRace() == Race.ELF)
           id = player.getSex() == Sex.MALE ? 6 : 7;
       else if (player.getRace() == Race.ORC)
       {
           if (!player.getClassId().isMage())
               id = player.getSex() == Sex.MALE ? 10 : 11;
           else
               id = player.getSex() == Sex.MALE ? 12 : 13;
       }
       else if (player.getRace() == Race.KAMAEL)
           id = player.getSex() == Sex.MALE ? 14 : 15;

       return getSet(id);
   }

   @Override
   public int size()
   {
       return _sets.size();
   }

   @Override
   public void clear()
   {
       _sets.clear();
   }

   @Override
   public void log()
   {
       info(String.format("loaded %d beauty shop set(s) count.", size()));
   }
}

 

 

Структуры для хранения данных:

 

package l2p.gameserver.model.beautyshop;

import gnu.trove.map.hash.TIntObjectHashMap;

public class BeautyShopSet
{
   private final int _id;
   private final TIntObjectHashMap<BeautyShopHairStyle> _hairStyles;
   private final TIntObjectHashMap<BeautyShopFace> _faces;

   public BeautyShopSet(int id, TIntObjectHashMap<BeautyShopHairStyle> hairStyles, TIntObjectHashMap<BeautyShopFace> faces)
   {
       _id = id;
       _hairStyles = hairStyles;
       _faces = faces;
   }

   public int getId()
   {
       return _id;
   }

   public TIntObjectHashMap<BeautyShopHairStyle> getHairStyles()
   {
       return _hairStyles;
   }

   public BeautyShopHairStyle getHairStyle(int id)
   {
       return _hairStyles.get(id);
   }

   public TIntObjectHashMap<BeautyShopFace> getFaces()
   {
       return _faces;
   }

   public BeautyShopFace getFace(int id)
   {
       return _faces.get(id);
   }
}


package l2p.gameserver.model.beautyshop;

public class BeautyShopFace
{
   private final int _id;
   private final long _adena;
   private final long _coins;
   private final long _resetPrice;

   public BeautyShopFace(int id, long adena, long coins, long resetPrice)
   {
       _id = id;
       _adena = adena;
       _coins = coins;
       _resetPrice = resetPrice;
   }

   public int getId()
   {
       return _id;
   }

   public long getAdena()
   {
       return _adena;
   }

   public long getCoins()
   {
       return _coins;
   }

   public long getResetPrice()
   {
       return _resetPrice;
   }
}


package l2p.gameserver.model.beautyshop;

import gnu.trove.map.hash.TIntObjectHashMap;

public class BeautyShopHairStyle
{
   private final int _id;
   private final long _adena;
   private final long _coins;
   private final long _resetPrice;

   private final TIntObjectHashMap<BeautyShopHairColor> _hairColors;

   public BeautyShopHairStyle(int id, long adena, long coins, long resetPrice, TIntObjectHashMap<BeautyShopHairColor> hairColors)
   {
       _id = id;
       _adena = adena;
       _coins = coins;
       _resetPrice = resetPrice;
       _hairColors = hairColors;
   }

   public int getId()
   {
       return _id;
   }

   public long getAdena()
   {
       return _adena;
   }

   public long getCoins()
   {
       return _coins;
   }

   public long getResetPrice()
   {
       return _resetPrice;
   }

   public TIntObjectHashMap<BeautyShopHairColor> getHairColors()
   {
       return _hairColors;
   }

   public BeautyShopHairColor getHairColor(int id)
   {
       return _hairColors.get(id);
   }
}


package l2p.gameserver.model.beautyshop;

public class BeautyShopHairColor
{
   private final int _id;
   private final long _adena;
   private final long _coins;

   public BeautyShopHairColor(int id, long adena, long coins)
   {
       _id = id;
       _adena = adena;
       _coins = coins;
   }

   public int getId()
   {
       return _id;
   }

   public long getAdena()
   {
       return _adena;
   }

   public long getCoins()
   {
       return _coins;
   }
}

 

 

В парсере вы можете заметить для чтения значений используется некие методы c названием Util.parseValue( ... ) - приводить их код я не буду, т.к. и так понятно как и что они делают - можете просто написать свою реализацию их или же использовать уже что-то готовое (методы, выполняющие примерно те же функции, насколько помню вроде как были и в оригинальном овере).

 

Далее нам необходимо внести мелкие изменения в пакеты UserInfo, CharInfo и GMViewCharacterInfo, для корректного отображения новой внешности.

 

Изменения простейшие, типа таких:

 

       _hairStyle = player.getNewHairStyle() > 0 ? player.getNewHairStyle() : player.getHairStyle();
       _hairColor = player.getNewHairColor() > 0 ? player.getNewHairColor() : player.getHairColor();
       _face = player.getNewFace() > 0 ? player.getNewFace() : player.getFace();

 

 

Ну и напоследок самое главное - все пакеты, связанные с салоном красоты.

Объяснять их содержимое думаю нет смысла - они достаточно просты и по их коду и так все понятно.

 

Но сначала не забудем добавить в GamePacketHandler обработку необходимых клиентских пакетов:

 

case 0xD7:
   msg = new RequestShowBeautyList();
   break;
case 0xD8:
   msg = new RequestRegistBeauty();
   break;
case 0xDA:
   msg = new RequestShowResetShopList();
   break;
case 0xEE:
   msg = new NotifyExitBeautyShop();
   break;

 

 

Ну и непосредственно сами пакеты.

 

Клиентские:

 

package l2p.gameserver.network.clientpackets;

import l2p.gameserver.model.Player;
import l2p.gameserver.network.serverpackets.ExResponseBeautyList;

public class RequestShowBeautyList extends L2GameClientPacket
{
   private int _type;

   @Override
   protected void readImpl()
   {
       _type = readD();
   }

   @Override
   protected void runImpl()
   {
       Player player = getClient().getActiveChar();

       if (player == null)
           return;

       player.sendPacket(new ExResponseBeautyList(player, _type));
   }
}


package l2p.gameserver.network.clientpackets;

import l2p.gameserver.Config;
import l2p.gameserver.data.xml.holder.BeautyShopHolder;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.beautyshop.BeautyShopSet;
import l2p.gameserver.network.serverpackets.ExResponseBeautyList;
import l2p.gameserver.network.serverpackets.ExResponseBeautyRegistReset;

public class RequestRegistBeauty extends L2GameClientPacket
{
   private int _hairStyle, _face, _hairColor;

   @Override
   protected void readImpl()
   {
       _hairStyle = readD();
       _face = readD();
       _hairColor = readD();
   }

   @Override
   protected void runImpl()
   {
       Player player = getClient().getActiveChar();

       if (player == null)
           return;

       long reqAdena = 0;
       long reqCoins = 0;
       boolean change = false;
       BeautyShopSet set = BeautyShopHolder.getInstance().getSet(player);

       if (set == null)
       {
           player.sendPacket(new ExResponseBeautyRegistReset(player, 0, 0), new ExResponseBeautyList(player, 0));
           return;
       }

       if (_hairStyle > 0 && _hairColor > 0 && (_hairStyle != player.getNewHairStyle() || _hairColor != player.getNewHairColor()))
       {
           if (set.getHairStyle(_hairStyle) == null || set.getHairStyle(_hairStyle).getHairColor(_hairColor) == null)
           {
               player.sendPacket(new ExResponseBeautyRegistReset(player, 0, 0), new ExResponseBeautyList(player, 0));
               return;
           }

           if (_hairStyle != player.getNewHairStyle())
           {
               reqAdena += set.getHairStyle(_hairStyle).getAdena() + set.getHairStyle(_hairStyle).getHairColor(_hairColor).getAdena();
               reqCoins += set.getHairStyle(_hairStyle).getCoins() + set.getHairStyle(_hairStyle).getHairColor(_hairColor).getCoins();
           }
           else
           {
               reqAdena += set.getHairStyle(_hairStyle).getHairColor(_hairColor).getAdena();
               reqCoins += set.getHairStyle(_hairStyle).getHairColor(_hairColor).getCoins();
           }

           change = true;
       }

       if (_face > 0 && _face != player.getNewFace())
       {
           if (set.getFace(_face) == null)
           {
               player.sendPacket(new ExResponseBeautyRegistReset(player, 0, 0), new ExResponseBeautyList(player, 0));
               return;
           }

           reqAdena += set.getFace(_face).getAdena();
           reqCoins += set.getFace(_face).getCoins();
           change = true;
       }

       if (!change || player.getItemCount(57) < reqAdena || player.getItemCount(Config.BS_COIN_ITEM_ID) < reqCoins)
       {
           player.sendPacket(new ExResponseBeautyRegistReset(player, 0, 0), new ExResponseBeautyList(player, 0));
           return;
       }

       if (reqAdena > 0)
           player.getInventory().destroyItemByItemId(57, reqAdena);

       if (reqCoins > 0)
           player.getInventory().destroyItemByItemId(Config.BS_COIN_ITEM_ID, reqCoins);

       if (_hairStyle > 0)
       {
           player.setNewHairStyle(_hairStyle);
           player.setNewHairColor(_hairColor);
       }

       if (_face > 0)
           player.setNewFace(_face);

       player.sendPacket(new ExResponseBeautyRegistReset(player, 0, 1), new ExResponseBeautyList(player, 0));
   }
}


package l2p.gameserver.network.clientpackets;

import l2p.gameserver.data.xml.holder.BeautyShopHolder;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.beautyshop.BeautyShopSet;
import l2p.gameserver.network.serverpackets.ExResponseBeautyRegistReset;

public class RequestShowResetShopList extends L2GameClientPacket
{
   private int _hairStyle, _face, _hairColor;

   @Override
   protected void readImpl()
   {
       _hairStyle = readD();
       _face = readD();
       _hairColor = readD();
   }

   @Override
   protected void runImpl()
   {
       Player player = getClient().getActiveChar();

       if (player == null)
           return;

       long reqAdena = 0;
       boolean reset = false;
       BeautyShopSet set = BeautyShopHolder.getInstance().getSet(player);

       if (set == null)
       {
           player.sendPacket(new ExResponseBeautyRegistReset(player, 1, 0));
           return;
       }

       if (_hairStyle > 0 && _hairColor > 0)
       {
           if (set.getHairStyle(_hairStyle) == null)
           {
               player.sendPacket(new ExResponseBeautyRegistReset(player, 1, 0));
               return;
           }

           reqAdena += set.getHairStyle(_hairStyle).getResetPrice();
           reset = true;
       }

       if (_face > 0)
       {
           if (set.getFace(_face) == null)
           {
               player.sendPacket(new ExResponseBeautyRegistReset(player, 1, 0));
               return;
           }

           reqAdena += set.getFace(_face).getResetPrice();
           reset = true;
       }

       if (!reset || player.getAdena() < reqAdena)
       {
           player.sendPacket(new ExResponseBeautyRegistReset(player, 1, 0));
           return;
       }

       player.getInventory().destroyItemByItemId(57, reqAdena);

       if (_hairStyle > 0)
       {
           player.setNewHairStyle(0);
           player.setNewHairColor(0);
       }

       if (_face > 0)
           player.setNewFace(0);

       player.sendPacket(new ExResponseBeautyRegistReset(player, 1, 1));
   }
}


package l2p.gameserver.network.clientpackets;

import l2p.gameserver.model.Player;

public class NotifyExitBeautyShop extends L2GameClientPacket
{
   @Override
   protected void readImpl()
   {}

   @Override
   protected void runImpl()
   {
       Player player = getClient().getActiveChar();

       if (player == null)
           return;

       player.broadcastCharInfo();
   }
}

 

 

И серверные пакеты:

 

package l2p.gameserver.network.serverpackets;

import l2p.gameserver.network.serverpackets.components.ServerPacket;

public class ExShowBeautyMenu extends L2GameServerPacket
{
   public int _type;    // 0 - выбор нового внешнего вида, 1 - возврат старого

   public ExShowBeautyMenu(int type)
   {
       _type = type;
   }

   @Override
   protected void writeImpl()
   {
       writeEx(ServerPacket.ExShowBeautyMenu);
       writeD(_type);
   }
}


package l2p.gameserver.network.serverpackets;

import l2p.gameserver.Config;
import l2p.gameserver.data.xml.holder.BeautyShopHolder;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.beautyshop.BeautyShopFace;
import l2p.gameserver.model.beautyshop.BeautyShopHairStyle;
import l2p.gameserver.model.beautyshop.BeautyShopSet;
import l2p.gameserver.network.serverpackets.components.ServerPacket;

public class ExResponseBeautyList extends L2GameServerPacket
{
   private int _type;
   private long _adena;
   private long _coins;
   private int[][] _data;
   private boolean _send = false;

   public ExResponseBeautyList(Player player, int type)
   {
       BeautyShopSet set = BeautyShopHolder.getInstance().getSet(player);

       if (set == null)
           return;

       int i = 0;

       if (type == 0)
       {
           _data = new int[set.getHairStyles().size()][2];

           for (BeautyShopHairStyle style : set.getHairStyles().valueCollection())
           {
               _data[i][0] = style.getId();
               _data[i][1] = 0;
               i++;
           }
       }
       else
       {
           _data = new int[set.getFaces().size()][2];

           for (BeautyShopFace face : set.getFaces().valueCollection())
           {
               _data[i][0] = face.getId();
               _data[i][1] = 0;
               i++;
           }
       }

       _type = type;
       _adena = player.getAdena();
       _coins = player.getItemCount(Config.BS_COIN_ITEM_ID);
       _send = true;
   }

   @Override
   protected void writeImpl()
   {
       if (!_send)
           return;

       writeEx(ServerPacket.ExResponseBeautyList);
       writeQ(_adena);
       writeQ(_coins);
       writeD(_type);
       writeD(_data.length);

       for (int[] element : _data)
       {
           writeD(element[0]);
           writeD(element[1]);
       }
   }
}


package l2p.gameserver.network.serverpackets;

import l2p.gameserver.Config;
import l2p.gameserver.model.Player;
import l2p.gameserver.network.serverpackets.components.ServerPacket;

public class ExResponseBeautyRegistReset extends L2GameServerPacket
{
   private int _type;
   private int _result;
   private int _hairStyle;
   private int _hairColor;
   private int _face;
   private long _adena;
   private long _coins;

   public ExResponseBeautyRegistReset(Player player, int type, int result)
   {
       _type = type;
       _result = result;
       _hairStyle = player.getNewHairStyle() > 0 ? player.getNewHairStyle() : player.getHairStyle();
       _hairColor = player.getNewHairColor() > 0 ? player.getNewHairColor() : player.getHairColor();
       _face = player.getNewFace() > 0 ? player.getNewFace() : player.getFace();
       _adena = player.getAdena();
       _coins = player.getItemCount(Config.BS_COIN_ITEM_ID);
   }

   @Override
   protected void writeImpl()
   {
       writeEx(ServerPacket.ExResponseBeautyRegistReset);
       writeQ(_adena);
       writeQ(_coins);
       writeD(_type);
       writeD(_result);
       writeD(_hairStyle);
       writeD(_face);
       writeD(_hairColor);
   }
}


package l2p.gameserver.network.serverpackets;

import l2p.gameserver.Config;
import l2p.gameserver.model.Player;
import l2p.gameserver.network.serverpackets.components.ServerPacket;

public class ExResponseResetList extends L2GameServerPacket
{
   private int _hairStyle;
   private int _hairColor;
   private int _face;
   private long _adena; 
   private long _coins;

   public ExResponseResetList(Player player)
   {
       _hairStyle = player.getHairStyle();
       _hairColor = player.getHairColor();
       _face = player.getFace();
       _adena = player.getAdena();
       _coins = player.getItemCount(Config.BS_COIN_ITEM_ID);

   }

   @Override
   protected void writeImpl()
   {
       writeEx(ServerPacket.ExResponseResetList);
       writeQ(_adena);
       writeQ(_coins);
       writeD(_hairStyle);
       writeD(_face);
       writeD(_hairColor);
   }
}

 

 

И опкоды этих пакетов:

 

   public static final int ExShowBeautyMenu = 0x13E;
   public static final int ExResponseBeautyList = 0x13F;
   public static final int ExResponseBeautyRegistReset = 0x140;
   public static final int ExResponseResetList = 0x141;

 

 

 

Ну вот собственно и все. Если я что и не описал или не пояснил - это в основном мелочи, до которых вы сами сможете без проблем додуматься.

  • Upvote 8

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация  

  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...