/* * Copyright (C) 2004-2014 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.io.PrintStream; import java.util.Arrays; import java.util.logging.Level; import com.l2jserver.Config; import com.l2jserver.gameserver.datatables.DoorTable; import com.l2jserver.gameserver.datatables.ItemTable; import com.l2jserver.gameserver.datatables.NpcData; import com.l2jserver.gameserver.datatables.SkillData; import com.l2jserver.gameserver.instancemanager.CastleManager; import com.l2jserver.gameserver.instancemanager.InstantWorldManager; import com.l2jserver.gameserver.instancemanager.ZoneManager; import com.l2jserver.gameserver.model.Elementals; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.L2Summon; import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.actor.templates.L2NpcTemplate; import com.l2jserver.gameserver.model.entity.Castle; import com.l2jserver.gameserver.model.items.L2Item; import com.l2jserver.gameserver.model.items.instance.L2ItemInstance; import com.l2jserver.gameserver.model.skills.Skill; import com.l2jserver.gameserver.model.zone.L2ZoneType; import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.SystemMessageId.SMLocalisation; public final class SystemMessage extends L2GameServerPacket { private static final SMParam[] EMPTY_PARAM_ARRAY = new SMParam[0]; private static final class SMParam { private final byte _type; private final Object _value; public SMParam(final byte type, final Object value) { _type = type; _value = value; } public final byte getType() { return _type; } public final Object getValue() { return _value; } public final String getStringValue() { return (String) _value; } public final int getIntValue() { return ((Integer) _value).intValue(); } public final long getLongValue() { return ((Long) _value).longValue(); } public final int[] getIntArrayValue() { return (int[]) _value; } } // TODO: UnAfraid: Check/Implement id's: 14,15. // 15 exists in goddess of destruction but also may works in h5 needs to be verified! // private static final byte TYPE_CLASS_ID = 15; // id 14 unknown private static final byte TYPE_DAMAGE = 16; // 603 (by otfnir) private static final byte TYPE_SUBCLASS_ID = 15; // 603 private static final byte TYPE_SYSTEM_STRING = 13; private static final byte TYPE_PLAYER_NAME = 12; private static final byte TYPE_DOOR_NAME = 11; private static final byte TYPE_INSTANCE_NAME = 10; private static final byte TYPE_ELEMENT_NAME = 9; // id 8 - same as 3 private static final byte TYPE_ZONE_NAME = 7; private static final byte TYPE_LONG_NUMBER = 6; private static final byte TYPE_CASTLE_NAME = 5; private static final byte TYPE_SKILL_NAME = 4; private static final byte TYPE_ITEM_NAME = 3; private static final byte TYPE_NPC_NAME = 2; private static final byte TYPE_INT_NUMBER = 1; private static final byte TYPE_TEXT = 0; public static final SystemMessage sendString(final String text) { if (text == null) { throw new NullPointerException(); } final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1); sm.addString(text); return sm; } public static final SystemMessage getSystemMessage(final SystemMessageId smId) { SystemMessage sm = smId.getStaticSystemMessage(); if (sm != null) { return sm; } sm = new SystemMessage(smId); if (smId.getParamCount() == 0) { smId.setStaticSystemMessage(sm); } return sm; } /** * Use {@link #getSystemMessage(SystemMessageId)} where possible instead * @param id * @return the system message associated to the given Id. */ public static SystemMessage getSystemMessage(int id) { return getSystemMessage(SystemMessageId.getSystemMessageId(id)); } private final SystemMessageId _smId; private SMParam[] _params; private int _paramIndex; private SystemMessage(final SystemMessageId smId) { final int paramCount = smId.getParamCount(); _smId = smId; _params = paramCount != 0 ? new SMParam[paramCount] : EMPTY_PARAM_ARRAY; } /** * Use SystemMessage.getSystemMessage(SystemMessageId smId) where possible instead * @param id * @deprecated */ @Deprecated private SystemMessage(final int id) { this(SystemMessageId.getSystemMessageId(id)); } private final void append(final SMParam param) { if (_paramIndex >= _params.length) { _params = Arrays.copyOf(_params, _paramIndex + 1); _smId.setParamCount(_paramIndex + 1); // 603-Test Show Damage _log.log(Level.INFO, "Wrong parameter count '" + (_paramIndex + 1) + "' for SystemMessageId: " + _smId); } _params[_paramIndex++] = param; } public final SystemMessage addString(final String text) { append(new SMParam(TYPE_TEXT, text)); return this; } /** * Appends a Castle name parameter type, the name will be read from CastleName-e.dat.<br> * <ul> * <li>1-9 Castle names</li> * <li>21 Fortress of Resistance</li> * <li>22-33 Clan Hall names</li> * <li>34 Devastated Castle</li> * <li>35 Bandit Stronghold</li> * <li>36-61 Clan Hall names</li> * <li>62 Rainbow Springs</li> * <li>63 Wild Beast Reserve</li> * <li>64 Fortress of the Dead</li> * <li>81-89 Territory names</li> * <li>90-100 null</li> * <li>101-121 Fortress names</li> * </ul> * @param number the conquerable entity * @return the system message with the proper parameter */ public final SystemMessage addCastleId(final int number) { append(new SMParam(TYPE_CASTLE_NAME, number)); return this; } public final SystemMessage addInt(final int number) { append(new SMParam(TYPE_INT_NUMBER, number)); return this; } public final SystemMessage addLong(final long number) { append(new SMParam(TYPE_LONG_NUMBER, number)); return this; } public final SystemMessage addCharName(final L2Character cha) { if (cha.isNpc()) { L2Npc npc = (L2Npc) cha; if (npc.getTemplate().isUsingServerSideName()) { return addString(npc.getTemplate().getName()); } return addNpcName(npc); } else if (cha.isPlayer()) { return addPcName(cha.getActingPlayer()); } else if (cha.isSummon()) { L2Summon summon = (L2Summon) cha; if (summon.getTemplate().isUsingServerSideName()) { return addString(summon.getTemplate().getName()); } return addNpcName(summon); } else if (cha.isDoor()) { L2DoorInstance door = (L2DoorInstance) cha; return addDoorName(door.getId()); } return addString(cha.getName()); } public final SystemMessage addPcName(final L2PcInstance pc) { append(new SMParam(TYPE_PLAYER_NAME, pc.getAppearance().getVisibleName())); return this; } /** * ID from doorData.xml * @param doorId * @return */ public SystemMessage addDoorName(int doorId) { append(new SMParam(TYPE_DOOR_NAME, doorId)); return this; } public final SystemMessage addNpcName(L2Npc npc) { return addNpcName(npc.getTemplate()); } public final SystemMessage addNpcName(final L2Summon npc) { return addNpcName(npc.getId()); } public final SystemMessage addNpcName(final L2NpcTemplate template) { if (template.isUsingServerSideName()) { return addString(template.getName()); } return addNpcName(template.getId()); } public final SystemMessage addNpcName(final int id) { append(new SMParam(TYPE_NPC_NAME, 1000000 + id)); return this; } public final SystemMessage addItemName(final L2ItemInstance item) { return addItemName(item.getId()); } public final SystemMessage addItemName(final L2Item item) { return addItemName(item.getId()); } public final SystemMessage addItemName(final int id) { L2Item item = ItemTable.getInstance().getTemplate(id); if (item.getDisplayId() != id) { return addString(item.getName()); } append(new SMParam(TYPE_ITEM_NAME, id)); return this; } public final SystemMessage addZoneName(final int x, final int y, final int z) { append(new SMParam(TYPE_ZONE_NAME, new int[] { x, y, z })); return this; } public final SystemMessage addSkillName(final Skill skill) { if (skill.getId() != skill.getDisplayId()) { return addString(skill.getName()); } return addSkillName(skill.getId(), skill.getLevel()); } public final SystemMessage addSkillName(final int id) { return addSkillName(id, 1); } public final SystemMessage addSkillName(final int id, final int lvl) { append(new SMParam(TYPE_SKILL_NAME, new int[] { id, lvl })); return this; } /** * Elemental name - 0(Fire) ... * @param type * @return */ public final SystemMessage addElemental(final int type) { append(new SMParam(TYPE_ELEMENT_NAME, type)); return this; } /** * ID from sysstring-e.dat * @param type * @return */ public final SystemMessage addSystemString(final int type) { append(new SMParam(TYPE_SYSTEM_STRING, type)); return this; } /** * Instance name from instantzonedata-e.dat * @param type id of instance * @return */ public final SystemMessage addInstanceName(final int type) { append(new SMParam(TYPE_INSTANCE_NAME, type)); return this; } public final SystemMessageId getSystemMessageId() { return _smId; } // 603 (by otfnir)-Start public final SystemMessage addDamage(final int targetObjectID, final int playerObjectID, final int damage) { append(new SMParam(TYPE_DAMAGE, new int[] {targetObjectID, playerObjectID, damage})); return this; } // 603 (by otfnir)-End // 603-Start public final SystemMessage addSubClassId(final int id) { append(new SMParam(TYPE_SUBCLASS_ID, id)); return this; } // 603-End public final SystemMessage getLocalizedMessage(final String lang) { if (!Config.L2JMOD_MULTILANG_SM_ENABLE || (_smId == SystemMessageId.S1)) { return this; } final SMLocalisation sml = _smId.getLocalisation(lang); if (sml == null) { return this; } final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1); final Object[] params = new Object[_paramIndex]; SMParam param; for (int i = 0; i < _paramIndex; i++) { param = _params[i]; switch (param.getType()) { case TYPE_TEXT: case TYPE_PLAYER_NAME: { params[i] = param.getValue(); break; } case TYPE_LONG_NUMBER: { params[i] = param.getValue(); break; } case TYPE_ITEM_NAME: { final L2Item item = ItemTable.getInstance().getTemplate(param.getIntValue()); params[i] = item == null ? "Unknown" : item.getName(); break; } case TYPE_CASTLE_NAME: { final Castle castle = CastleManager.getInstance().getCastleById(param.getIntValue()); params[i] = castle == null ? "Unknown" : castle.getName(); break; } case TYPE_INT_NUMBER: { params[i] = param.getValue(); break; } case TYPE_NPC_NAME: { final L2NpcTemplate template = NpcData.getInstance().getTemplate(param.getIntValue()); params[i] = template == null ? "Unknown" : template.getName(); break; } case TYPE_ELEMENT_NAME: { params[i] = Elementals.getElementName((byte) param.getIntValue()); break; } case TYPE_SYSTEM_STRING: { params[i] = "SYS-S-" + param.getIntValue(); // writeD(param.getIntValue()); break; } case TYPE_INSTANCE_NAME: { final String instanceName = InstantWorldManager.getInstance().getInstantWorldIdName(param.getIntValue()); params[i] = instanceName == null ? "Unknown" : instanceName; break; } case TYPE_DOOR_NAME: { final L2DoorInstance door = DoorTable.getInstance().getDoor(param.getIntValue()); params[i] = door == null ? "Unknown" : door.getName(); break; } case TYPE_SKILL_NAME: { final int[] array = param.getIntArrayValue(); final Skill skill = SkillData.getInstance().getSkill(array[0], array[1]); params[i] = skill == null ? "Unknown" : skill.getName(); break; } case TYPE_ZONE_NAME: { final int[] array = param.getIntArrayValue(); final L2ZoneType zone = ZoneManager.getInstance().getZone(array[0], array[1], array[2], L2ZoneType.class); params[i] = zone == null ? "Unknown ZONE-N-" + Arrays.toString(array) : zone.getName(); break; } } } sm.addString(sml.getLocalisation(params)); return sm; } public final void printMe(PrintStream out) { out.println(0x62); out.println(_smId.getId()); out.println(_paramIndex); SMParam param; for (int i = 0; i < _paramIndex; i++) { param = _params[i]; out.println(param.getType()); switch (param.getType()) { case TYPE_TEXT: case TYPE_PLAYER_NAME: { out.println(param.getStringValue()); break; } case TYPE_LONG_NUMBER: { out.println(param.getLongValue()); break; } case TYPE_ITEM_NAME: case TYPE_CASTLE_NAME: case TYPE_INT_NUMBER: case TYPE_NPC_NAME: case TYPE_ELEMENT_NAME: case TYPE_SYSTEM_STRING: case TYPE_INSTANCE_NAME: case TYPE_DOOR_NAME: { out.println(param.getIntValue()); break; } case TYPE_SKILL_NAME: { final int[] array = param.getIntArrayValue(); out.println(array[0]); // SkillId out.println(array[1]); // SkillLevel break; } case TYPE_ZONE_NAME: { final int[] array = param.getIntArrayValue(); out.println(array[0]); // x out.println(array[1]); // y out.println(array[2]); // z break; } // 603 (by otfnir)-Start case TYPE_DAMAGE: { final int[] array = param.getIntArrayValue(); out.println(array[0]); // target out.println(array[1]); // player out.println(array[2]); // damage break; } // 603 (by otfnir)-End // 603-Start case TYPE_SUBCLASS_ID: { out.println(param.getIntValue()); break; } // 603-End } } } @Override protected final void writeImpl() { writeC(0x62); writeH(_smId.getId()); // 603 writeC(_paramIndex); // 603 SMParam param; for (int i = 0; i < _paramIndex; i++) { param = _params[i]; writeC(param.getType()); // 603 switch (param.getType()) { case TYPE_TEXT: case TYPE_PLAYER_NAME: { writeS(param.getStringValue()); break; } case TYPE_LONG_NUMBER: { writeQ(param.getLongValue()); break; } case TYPE_ITEM_NAME: case TYPE_CASTLE_NAME: case TYPE_INT_NUMBER: case TYPE_NPC_NAME: case TYPE_ELEMENT_NAME: case TYPE_SYSTEM_STRING: case TYPE_INSTANCE_NAME: case TYPE_DOOR_NAME: { writeD(param.getIntValue()); break; } case TYPE_SKILL_NAME: { final int[] array = param.getIntArrayValue(); writeD(array[0]); // SkillId writeH(array[1]); // 603 // SkillLevel break; } case TYPE_ZONE_NAME: { final int[] array = param.getIntArrayValue(); writeD(array[0]); // x writeD(array[1]); // y writeD(array[2]); // z break; } // 603 (by otfnir)-Start case TYPE_DAMAGE: { final int[] array = param.getIntArrayValue(); writeD(array[0]); // target writeD(array[1]); // player writeD(array[2]); // damage break; } // 603 (by otfnir)-End // 603-Start case TYPE_SUBCLASS_ID: { writeH(param.getIntValue()); break; } // 603-End } } } }