/*
* Copyright (C) 2004-2015 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server 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.
*
* L2J Server 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 com.l2jserver.gameserver.network.serverpackets;
import com.l2jserver.gameserver.data.xml.impl.ExperienceData;
import com.l2jserver.gameserver.enums.UserInfoType;
import com.l2jserver.gameserver.instancemanager.RaidBossPointsManager;
import com.l2jserver.gameserver.model.Elementals;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.L2Party;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.zone.ZoneId;
/**
* @author Sdw, UnAfraid
*/
public class UserInfo extends AbstractMaskPacket<UserInfoType>
{
private final L2PcInstance _activeChar;
private final int _relation;
private final int _runSpd;
private final int _walkSpd;
private final int _swimRunSpd;
private final int _swimWalkSpd;
private final int _flRunSpd = 0;
private final int _flWalkSpd = 0;
private final int _flyRunSpd;
private final int _flyWalkSpd;
private final double _moveMultiplier;
private int _enchantLevel = 0;
private int _armorEnchant = 0;
private String _title;
private final byte[] _masks = new byte[]
{
(byte) 0x00,
(byte) 0x00,
(byte) 0x00
};
private int _initSize = 5;
public UserInfo(L2PcInstance cha)
{
this(cha, true);
}
public UserInfo(L2PcInstance cha, boolean addAll)
{
_activeChar = cha;
_relation = calculateRelation(cha);
_moveMultiplier = cha.getMovementSpeedMultiplier();
_runSpd = (int) Math.round(cha.getRunSpeed() / _moveMultiplier);
_walkSpd = (int) Math.round(cha.getWalkSpeed() / _moveMultiplier);
_swimRunSpd = (int) Math.round(cha.getSwimRunSpeed() / _moveMultiplier);
_swimWalkSpd = (int) Math.round(cha.getSwimWalkSpeed() / _moveMultiplier);
_flyRunSpd = cha.isFlying() ? _runSpd : 0;
_flyWalkSpd = cha.isFlying() ? _walkSpd : 0;
_enchantLevel = cha.getInventory().getWeaponEnchant();
_armorEnchant = cha.getInventory().getArmorMinEnchant();
_title = cha.getTitle();
if (cha.isGM() && cha.isInvisible())
{
_title = "[Invisible]";
}
if (addAll)
{
addComponentType(UserInfoType.values());
}
}
@Override
protected byte[] getMasks()
{
return _masks;
}
@Override
protected void onNewMaskAdded(UserInfoType component)
{
calcBlockSize(component);
}
private void calcBlockSize(UserInfoType type)
{
switch (type)
{
case BASIC_INFO:
{
_initSize += type.getBlockLength() + (_activeChar.getName().length() * 2);
break;
}
case CLAN:
{
_initSize += type.getBlockLength() + (_title.length() * 2);
break;
}
default:
{
_initSize += type.getBlockLength();
break;
}
}
}
@Override
protected void writeImpl()
{
writeC(0x32);
writeD(_activeChar.getObjectId());
writeD(_initSize);
writeH(23);
writeB(_masks);
if (containsMask(UserInfoType.RELATION))
{
writeD(_relation);
}
if (containsMask(UserInfoType.BASIC_INFO))
{
writeH(16 + (_activeChar.getName().length() * 2));
writeString(_activeChar.getName());
writeC(_activeChar.isGM() ? 0x01 : 0x00);
writeC(_activeChar.getRace().ordinal());
writeC(_activeChar.getAppearance().getSex() ? 0x01 : 0x00);
writeD(_activeChar.getBaseClass());
writeD(_activeChar.getClassId().getId());
writeC(_activeChar.getLevel());
}
if (containsMask(UserInfoType.BASE_STATS))
{
writeH(18);
writeH(_activeChar.getSTR());
writeH(_activeChar.getDEX());
writeH(_activeChar.getCON());
writeH(_activeChar.getINT());
writeH(_activeChar.getWIT());
writeH(_activeChar.getMEN());
writeH(_activeChar.getLUC());
writeH(_activeChar.getCHA());
}
if (containsMask(UserInfoType.MAX_HPCPMP))
{
writeH(14);
writeD(_activeChar.getMaxHp());
writeD(_activeChar.getMaxMp());
writeD(_activeChar.getMaxCp());
}
if (containsMask(UserInfoType.CURRENT_HPMPCP_EXP_SP))
{
writeH(38);
writeD((int) Math.round(_activeChar.getCurrentHp()));
writeD((int) Math.round(_activeChar.getCurrentMp()));
writeD((int) Math.round(_activeChar.getCurrentCp()));
writeQ(_activeChar.getSp());
writeQ(_activeChar.getExp());
writeF((float) (_activeChar.getExp() - ExperienceData.getInstance().getExpForLevel(_activeChar.getLevel())) / (ExperienceData.getInstance().getExpForLevel(_activeChar.getLevel() + 1) - ExperienceData.getInstance().getExpForLevel(_activeChar.getLevel())));
}
if (containsMask(UserInfoType.ENCHANTLEVEL))
{
writeH(4);
writeC(_enchantLevel);
writeC(_armorEnchant);
}
if (containsMask(UserInfoType.APPAREANCE))
{
writeH(15);
writeD(_activeChar.getVisualHair());
writeD(_activeChar.getVisualHairColor());
writeD(_activeChar.getVisualFace());
writeC(_activeChar.isHairAccessoryEnabled() ? 0x01 : 0x00);
}
if (containsMask(UserInfoType.STATUS))
{
writeH(6);
writeC(_activeChar.getMountType().ordinal());
writeC(_activeChar.getPrivateStoreType().getId());
writeC(_activeChar.hasDwarvenCraft() ? 1 : 0);
writeC(_activeChar.getAbilityPointsUsed());
}
if (containsMask(UserInfoType.STATS))
{
writeH(56);
writeH(_activeChar.getActiveWeaponItem() != null ? 40 : 20);
writeD(_activeChar.getPAtk(null));
writeD(_activeChar.getPAtkSpd());
writeD(_activeChar.getPDef(null));
writeD(_activeChar.getEvasionRate(null));
writeD(_activeChar.getAccuracy());
writeD(_activeChar.getCriticalHit(null, null));
writeD(_activeChar.getMAtk(null, null));
writeD(_activeChar.getMAtkSpd());
writeD(_activeChar.getPAtkSpd()); // Seems like atk speed - 1
writeD(_activeChar.getMagicEvasionRate(null));
writeD(_activeChar.getMDef(null, null));
writeD(_activeChar.getMagicAccuracy());
writeD(_activeChar.getMCriticalHit(null, null));
}
if (containsMask(UserInfoType.ELEMENTALS))
{
writeH(14);
writeH(_activeChar.getDefenseElementValue(Elementals.FIRE));
writeH(_activeChar.getDefenseElementValue(Elementals.WATER));
writeH(_activeChar.getDefenseElementValue(Elementals.WIND));
writeH(_activeChar.getDefenseElementValue(Elementals.EARTH));
writeH(_activeChar.getDefenseElementValue(Elementals.HOLY));
writeH(_activeChar.getDefenseElementValue(Elementals.DARK));
}
if (containsMask(UserInfoType.POSITION))
{
writeH(18);
writeD(_activeChar.getX());
writeD(_activeChar.getY());
writeD(_activeChar.getZ());
writeD(_activeChar.isInVehicle() ? _activeChar.getVehicle().getObjectId() : 0);
}
if (containsMask(UserInfoType.SPEED))
{
writeH(18);
writeH(_runSpd);
writeH(_walkSpd);
writeH(_swimRunSpd);
writeH(_swimWalkSpd);
writeH(_flRunSpd);
writeH(_flWalkSpd);
writeH(_flyRunSpd);
writeH(_flyWalkSpd);
}
if (containsMask(UserInfoType.MULTIPLIER))
{
writeH(18);
writeF(_moveMultiplier);
writeF(_activeChar.getAttackSpeedMultiplier());
}
if (containsMask(UserInfoType.COL_RADIUS_HEIGHT))
{
writeH(18);
writeF(_activeChar.getCollisionRadius());
writeF(_activeChar.getCollisionHeight());
}
if (containsMask(UserInfoType.ATK_ELEMENTAL))
{
writeH(5);
byte attackAttribute = _activeChar.getAttackElement();
writeC(attackAttribute);
writeH(_activeChar.getAttackElementValue(attackAttribute));
}
if (containsMask(UserInfoType.CLAN))
{
writeH(32 + (_title.length() * 2));
writeString(_title);
writeH(_activeChar.getPledgeType());
writeD(_activeChar.getClanId());
writeD(_activeChar.getClanCrestLargeId());
writeD(_activeChar.getClanCrestId());
writeC(_activeChar.isClanLeader() ? -1 : 0x00);
writeD(_activeChar.getClanPrivileges().getBitmask());
writeD(_activeChar.getAllyId());
writeD(_activeChar.getAllyCrestId());
writeC(_activeChar.isInPartyMatchRoom() ? 0x01 : 0x00);
}
if (containsMask(UserInfoType.SOCIAL))
{
writeH(22);
writeC(_activeChar.getPvpFlag());
writeD(_activeChar.getKarma());
writeC(_activeChar.isNoble() ? 0x01 : 0x00);
writeC(_activeChar.isHero() ? 0x01 : 0x00);
writeC(_activeChar.getPledgeClass());
writeD(_activeChar.getPkKills());
writeD(_activeChar.getPvpKills());
writeD(_activeChar.getRecomLeft());
}
if (containsMask(UserInfoType.VITA_FAME))
{
writeH(15);
writeD(_activeChar.getVitalityPoints());
writeC(0x00); // Vita Bonus
writeD(_activeChar.getFame());
writeD(RaidBossPointsManager.getInstance().getPointsByOwnerId(_activeChar.getObjectId()));
}
if (containsMask(UserInfoType.SLOTS))
{
writeH(9);
writeC(_activeChar.getInventory().getTalismanSlots()); // Confirmed
writeC(_activeChar.getInventory().getBroochJewelSlots()); // Confirmed
writeC(_activeChar.getTeam().getId()); // Confirmed
writeC(0x00); // (1 = Red, 2 = White, 3 = White Pink) dotted ring on the floor
writeC(0x00);
writeC(0x00);
writeC(0x00);
}
if (containsMask(UserInfoType.MOVEMENTS))
{
writeH(4);
writeC(_activeChar.isInsideZone(ZoneId.WATER) ? 1 : _activeChar.isFlyingMounted() ? 2 : 0);
writeC(_activeChar.isRunning() ? 0x01 : 0x00);
}
if (containsMask(UserInfoType.COLOR))
{
writeH(10);
writeD(_activeChar.getAppearance().getNameColor());
writeD(_activeChar.getAppearance().getTitleColor());
}
if (containsMask(UserInfoType.INVENTORY_LIMIT))
{
writeH(9);
writeH(0x00);
writeH(0x00);
writeH(_activeChar.getInventoryLimit());
writeC(0x00); // if greater than 1 show the attack cursor when interacting
}
if (containsMask(UserInfoType.UNK_3))
{
writeH(9);
writeC(0x00);
writeH(0x00);
writeD(0x00);
}
}
private int calculateRelation(L2PcInstance activeChar)
{
int relation = 0;
final L2Party party = activeChar.getParty();
final L2Clan clan = activeChar.getClan();
if (party != null)
{
relation |= 0x08; // Party member
if (party.getLeader() == _activeChar)
{
relation |= 0x10; // Party leader
}
}
if (clan != null)
{
relation |= 0x20; // Clan member
if (clan.getLeaderId() == activeChar.getObjectId())
{
relation |= 0x40; // Clan leader
}
}
if (activeChar.isInSiege())
{
relation |= 0x80; // In siege
}
return relation;
}
}