/*
* 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 java.util.Set;
import com.l2jserver.Config;
import com.l2jserver.gameserver.data.sql.impl.ClanTable;
import com.l2jserver.gameserver.enums.NpcInfoType;
import com.l2jserver.gameserver.enums.Team;
import com.l2jserver.gameserver.instancemanager.TownManager;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2GuardInstance;
import com.l2jserver.gameserver.model.skills.AbnormalVisualEffect;
import com.l2jserver.gameserver.model.zone.ZoneId;
/**
* @author UnAfraid
*/
public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
{
private final L2Npc _npc;
private final byte[] _masks = new byte[]
{
(byte) 0x00,
(byte) 0x0C,
(byte) 0x0C,
(byte) 0x00,
(byte) 0x00
};
private int _initSize = 0;
private int _blockSize = 0;
private int _clanCrest = 0;
private int _clanLargeCrest = 0;
private int _allyCrest = 0;
private int _allyId = 0;
private int _clanId = 0;
private int _statusMask = 0;
private final Set<AbnormalVisualEffect> _abnormalVisualEffects;
public NpcInfo(L2Npc npc)
{
_npc = npc;
_abnormalVisualEffects = npc.getCurrentAbnormalVisualEffects();
if (npc.getTemplate().getDisplayId() != npc.getTemplate().getId())
{
_masks[2] |= 0x10;
}
addComponentType(NpcInfoType.ATTACKABLE, NpcInfoType.UNKNOWN1, NpcInfoType.TITLE, NpcInfoType.ID, NpcInfoType.POSITION, NpcInfoType.ALIVE, NpcInfoType.RUNNING);
if (npc.getHeading() > 0)
{
addComponentType(NpcInfoType.HEADING);
}
if ((npc.getStat().getPAtkSpd() > 0) || (npc.getStat().getMAtkSpd() > 0))
{
addComponentType(NpcInfoType.ATK_CAST_SPEED);
}
if (npc.getRunSpeed() > 0)
{
addComponentType(NpcInfoType.SPEED_MULTIPLIER);
}
if ((npc.getLeftHandItem() > 0) || (npc.getRightHandItem() > 0))
{
addComponentType(NpcInfoType.EQUIPPED);
}
if (npc.getTeam() != Team.NONE)
{
addComponentType(NpcInfoType.TEAM);
}
if (npc.getState() > 0)
{
addComponentType(NpcInfoType.DISPLAY_EFFECT);
}
if (npc.isInsideZone(ZoneId.WATER) || npc.isFlying())
{
addComponentType(NpcInfoType.SWIM_OR_FLY);
}
if (npc.isFlying())
{
addComponentType(NpcInfoType.FLYING);
}
if (npc.getMaxHp() > 0)
{
addComponentType(NpcInfoType.MAX_HP);
}
if (npc.getMaxMp() > 0)
{
addComponentType(NpcInfoType.MAX_MP);
}
if (npc.getCurrentHp() <= npc.getMaxHp())
{
addComponentType(NpcInfoType.CURRENT_HP);
}
if (npc.getCurrentMp() <= npc.getMaxMp())
{
addComponentType(NpcInfoType.CURRENT_MP);
}
if (npc.getTemplate().getDisplayId() != npc.getTemplate().getId())
{
addComponentType(NpcInfoType.NAME);
}
if (!_abnormalVisualEffects.isEmpty())
{
addComponentType(NpcInfoType.ABNORMALS);
}
if (npc.getEnchantEffect() > 0)
{
addComponentType(NpcInfoType.ENCHANT);
}
if ((npc.getTransformation() != null) && (npc.getTransformation().getId() > 0))
{
addComponentType(NpcInfoType.TRANSFORMATION);
}
if (npc.isInsideZone(ZoneId.TOWN) && (npc.getCastle() != null) && (Config.SHOW_CREST_WITHOUT_QUEST || npc.getCastle().getShowNpcCrest()) && (npc.getCastle().getOwnerId() != 0))
{
int townId = TownManager.getTown(npc.getX(), npc.getY(), npc.getZ()).getTownId();
if ((townId != 33) && (townId != 22))
{
L2Clan clan = ClanTable.getInstance().getClan(npc.getCastle().getOwnerId());
_clanId = clan.getId();
_clanCrest = clan.getCrestId();
_clanLargeCrest = clan.getCrestLargeId();
_allyCrest = clan.getAllyCrestId();
_allyId = clan.getAllyId();
addComponentType(NpcInfoType.CLAN);
}
}
addComponentType(NpcInfoType.UNKNOWN8);
// TODO: Confirm me
if (npc.isInCombat())
{
_statusMask |= 0x01;
}
if (npc.isDead())
{
_statusMask |= 0x02;
}
if (npc.isTargetable())
{
_statusMask |= 0x04;
}
if (npc.isShowName())
{
_statusMask |= 0x08;
}
if (_statusMask != 0)
{
addComponentType(NpcInfoType.VISUAL_STATE);
}
}
@Override
protected byte[] getMasks()
{
return _masks;
}
@Override
protected void onNewMaskAdded(NpcInfoType component)
{
calcBlockSize(_npc, component);
}
private void calcBlockSize(L2Npc npc, NpcInfoType type)
{
switch (type)
{
case ATTACKABLE:
case UNKNOWN1:
{
_initSize += type.getBlockLength();
break;
}
case TITLE:
{
_initSize += type.getBlockLength() + (npc.getTitle().length() * 2);
break;
}
case NAME:
{
_blockSize += type.getBlockLength() + (npc.getName().length() * 2);
break;
}
default:
{
_blockSize += type.getBlockLength();
break;
}
}
}
@Override
protected void writeImpl()
{
writeC(0x0C);
writeD(_npc.getObjectId());
writeC(0x00); // // 0=teleported 1=default 2=summoned
writeH(37); // mask_bits_37
writeB(_masks);
// Block 1
writeC(_initSize);
if (containsMask(NpcInfoType.ATTACKABLE))
{
writeC(_npc.isAttackable() && !(_npc instanceof L2GuardInstance) ? 0x01 : 0x00);
}
if (containsMask(NpcInfoType.UNKNOWN1))
{
writeD(0x00); // unknown
}
if (containsMask(NpcInfoType.TITLE))
{
writeS(_npc.getTitle());
}
// Block 2
writeH(_blockSize);
if (containsMask(NpcInfoType.ID))
{
writeD(_npc.getTemplate().getDisplayId() + 1000000);
}
if (containsMask(NpcInfoType.POSITION))
{
writeD(_npc.getX());
writeD(_npc.getY());
writeD(_npc.getZ());
}
if (containsMask(NpcInfoType.HEADING))
{
writeD(_npc.getHeading());
}
if (containsMask(NpcInfoType.UNKNOWN2))
{
writeD(0x00); // Unknown
}
if (containsMask(NpcInfoType.ATK_CAST_SPEED))
{
writeD(_npc.getPAtkSpd());
writeD(_npc.getMAtkSpd());
}
if (containsMask(NpcInfoType.SPEED_MULTIPLIER))
{
_buf.putFloat((float) _npc.getStat().getMovementSpeedMultiplier());
_buf.putFloat(_npc.getStat().getAttackSpeedMultiplier());
}
if (containsMask(NpcInfoType.EQUIPPED))
{
writeD(_npc.getRightHandItem());
writeD(0x00); // Armor id?
writeD(_npc.getLeftHandItem());
}
if (containsMask(NpcInfoType.ALIVE))
{
writeC(_npc.isDead() ? 0x00 : 0x01);
}
if (containsMask(NpcInfoType.RUNNING))
{
writeC(_npc.isRunning() ? 0x01 : 0x00);
}
if (containsMask(NpcInfoType.SWIM_OR_FLY))
{
writeC(_npc.isInsideZone(ZoneId.WATER) ? 0x01 : _npc.isFlying() ? 0x02 : 0x00);
}
if (containsMask(NpcInfoType.TEAM))
{
writeC(_npc.getTeam().getId());
}
if (containsMask(NpcInfoType.ENCHANT))
{
writeD(_npc.getEnchantEffect());
}
if (containsMask(NpcInfoType.FLYING))
{
writeD(_npc.isFlying() ? 0x01 : 00);
}
if (containsMask(NpcInfoType.CLONE))
{
writeD(0x00); // Player ObjectId with Decoy
}
if (containsMask(NpcInfoType.UNKNOWN8))
{
// No visual effect
writeD(0x00); // Unknown
}
if (containsMask(NpcInfoType.DISPLAY_EFFECT))
{
writeD(_npc.getState());
}
if (containsMask(NpcInfoType.TRANSFORMATION))
{
writeD(0x00); // Transformation ID
}
if (containsMask(NpcInfoType.CURRENT_HP))
{
writeD((int) _npc.getCurrentHp());
}
if (containsMask(NpcInfoType.CURRENT_MP))
{
writeD((int) _npc.getCurrentMp());
}
if (containsMask(NpcInfoType.MAX_HP))
{
writeD(_npc.getMaxHp());
}
if (containsMask(NpcInfoType.MAX_MP))
{
writeD(_npc.getMaxMp());
}
if (containsMask(NpcInfoType.UNKNOWN11))
{
writeC(0x00); // 2 - do some animation on spawn
}
if (containsMask(NpcInfoType.UNKNOWN12))
{
writeD(0x00);
writeD(0x00);
}
if (containsMask(NpcInfoType.NAME))
{
writeS(_npc.getName());
}
if (containsMask(NpcInfoType.NAME_NPCSTRINGID))
{
writeD(-1); // NPCStringId for name
}
if (containsMask(NpcInfoType.TITLE_NPCSTRINGID))
{
writeD(-1); // NPCStringId for title
}
if (containsMask(NpcInfoType.PVP_FLAG))
{
writeC(0x00); // PVP flag
}
if (containsMask(NpcInfoType.NAME_COLOR))
{
writeD(0x00); // Name color
}
if (containsMask(NpcInfoType.CLAN))
{
writeD(_clanId);
writeD(_clanCrest);
writeD(_clanLargeCrest);
writeD(_allyId);
writeD(_allyCrest);
}
if (containsMask(NpcInfoType.VISUAL_STATE))
{
writeC(_statusMask);
}
if (containsMask(NpcInfoType.ABNORMALS))
{
writeH(_abnormalVisualEffects.size());
for (AbnormalVisualEffect abnormalVisualEffect : _abnormalVisualEffects)
{
writeH(abnormalVisualEffect.getClientId());
}
}
}
}