Рейтинг темы:
  • 0 Голос(ов) - 0 в среднем
  • 1
  • 2
  • 3
  • 4
  • 5
Beauty Shop
#1
Думаю все в курсе, что в Lindvior ввели Beauty Shop (салон красоты), предназначенный для изменения внешнего вида персонажей (прически, цвета волос, лица).

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

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

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

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

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

Хранить данные мы будем в xml-файле следующей структуры:
[SRC="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>
[/SRC]

И для примера фрагмент xml с данными
[SRC="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>
[/SRC]

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

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

Парсер:
[SRC="java"]
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()Wink
{
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()Wink
{
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()Wink
{
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()Wink
{
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()Wink
{
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));
}
}
}
[/SRC]

Хранилище:
[SRC="java"]
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()));
}
}
[/SRC]

Структуры для хранения данных:
[SRC="java"]
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;
}
}
[/SRC]

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

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

Изменения простейшие, типа таких:
[SRC="java"]
_hairStyle = player.getNewHairStyle() > 0 ? player.getNewHairStyle() : player.getHairStyle();
_hairColor = player.getNewHairColor() > 0 ? player.getNewHairColor() : player.getHairColor();
_face = player.getNewFace() > 0 ? player.getNewFace() : player.getFace();
[/SRC]

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

Но сначала не забудем добавить в GamePacketHandler обработку необходимых клиентских пакетов:
[SRC="java"]
case 0xD7:
msg = new RequestShowBeautyList();
break;
case 0xD8:
msg = new RequestRegistBeauty();
break;
case 0xDA:
msg = new RequestShowResetShopList();
break;
case 0xEE:
msg = new NotifyExitBeautyShop();
break;
[/SRC]

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

Клиентские:
[SRC="java"]
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();
}
}
[/SRC]

И серверные пакеты:
[SRC="java"]
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);
}
}
[/SRC]

И опкоды этих пакетов:
[SRC="java"]
public static final int ExShowBeautyMenu = 0x13E;
public static final int ExResponseBeautyList = 0x13F;
public static final int ExResponseBeautyRegistReset = 0x140;
public static final int ExResponseResetList = 0x141;

[/SRC]


Ну вот собственно и все. Если я что и не описал или не пояснил - это в основном мелочи, до которых вы сами сможете без проблем додуматься.
Ответ
#2
Ваще от души, благодарочка) Wink
:redlol:
Ответ
#3
Большое спасибо будет что скопи пастить :redlol:
Помог не забудь "Спасибо" Smile
Ответ
#4
ну дык реализация то достаточно примитивная - у меня самого реализация почти всего этого заняла где-то один день всего, ну и еще потом просто по мелочам корректировал возникавшие мелкие ньюансы.
Ответ
#5
Спасибо, дополнил имеющееся.
Ответ
#6
Приятно видеть такие темы среди тонн <...>, аки бальзам на душу. Месье, вы - настоящий джентльмен! Мое почтение.
Ответ
#7
И правда ТС заслуживает уважение! Как подметил Зератул, приятно видеть лучик света среди океана тьмы Big GrinBig Grin)

Вклад хотябы малой доли знаний с каждого из нас как сделал Гаикотсу, и вёрнет ЗГ к прежднему виду. Где было тонна мануалов гайдов каждую неделю где люди спрашивали друг друга и получали ответ.)) Хорошее было время)
Ответ
#8
good work ~
Ответ
#9
Кстати вопрос: зачем древо ифов вместо кейса?)
[Изображение: 4e38c909fcd08c5fcdf363b54a62.png]
Ответ
#10
Zubastic Написал:Кстати вопрос: зачем древо ифов вместо кейса?)

Ты бы уточнил о чём говоришь.
Fortuna - non penis, in manus non recipe.
Ответ


Возможно похожие темы ...
Тема Автор Ответы Просмотры Последний пост
  Item Mall/Prime Shop что такое и с чем его едят? VISTALL 152 116,812 02-18-2021, 12:01 PM
Последний пост: RyslanS
  CommunityBoard + GM Shop реализация michail_ST 5 1,684 04-21-2016, 01:20 PM
Последний пост: flopix
  Donate Shop [Lucera] labrador116 23 10,867 03-12-2014, 03:08 PM
Последний пост: labrador116
  Item Mall / Prime Shop L2jServer Freya High Five Part 5 Blackmau5 9 5,756 12-15-2012, 05:22 PM
Последний пост: Blackmau5
  [Share] GM-Shop Newbie 0 1,197 08-04-2012, 03:40 PM
Последний пост: Newbie
  Gm Shop помогите сделать.. Kanabis 10 2,743 04-27-2012, 02:11 PM
Последний пост: rage
  ГМ шоп \ GM shop Puma1414 2 1,565 01-28-2012, 01:52 AM
Последний пост: Puma1414
  Проблема с созданием GM Shop'а Galiaf 5 2,264 03-08-2011, 01:58 AM
Последний пост: Deazer
  редактировать gm shop,buffer [Red Dragon] 9 3,630 08-13-2010, 07:45 PM
Последний пост: [Red Dragon]
  GM-Shop для сборки Phoenix Roo 4 2,790 06-19-2010, 10:15 AM
Последний пост: Tonchi

Перейти к форуму:


Пользователи, просматривающие эту тему: 1 Гость(ей)