/* * This program 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. * * This program 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 . */ package com.l2jserver.gameserver.model; import com.l2jserver.gameserver.handler.ActionHandler; import com.l2jserver.gameserver.handler.ActionShiftHandler; import com.l2jserver.gameserver.handler.IActionHandler; import com.l2jserver.gameserver.idfactory.IdFactory; import com.l2jserver.gameserver.instancemanager.InstanceManager; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.actor.knownlist.ObjectKnownList; import com.l2jserver.gameserver.model.actor.poly.ObjectPoly; import com.l2jserver.gameserver.model.actor.position.ObjectPosition; import com.l2jserver.gameserver.model.entity.Instance; import com.l2jserver.gameserver.model.zone.ZoneId; import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.serverpackets.ActionFailed; import com.l2jserver.gameserver.network.serverpackets.ExSendUIEvent; import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket; /** * Mother class of all objects in the world which ones is it possible to interact (PC, NPC, Item...)
*
* L2Object :
*
*
  • L2Character
  • L2ItemInstance
  • */ public abstract class L2Object { private boolean _isVisible; // Object visibility private ObjectKnownList _knownList; private String _name; private int _objectId; // Object identifier private ObjectPoly _poly; private ObjectPosition _position; private int _instanceId = 0; private InstanceType _instanceType = null; public L2Object(int objectId) { setInstanceType(InstanceType.L2Object); _objectId = objectId; initKnownList(); initPosition(); } public static enum InstanceType { L2Object(null), L2ItemInstance(L2Object), L2Character(L2Object), L2Npc(L2Character), L2Playable(L2Character), L2Summon(L2Playable), L2Decoy(L2Character), L2Trap(L2Character), L2PcInstance(L2Playable), L2NpcInstance(L2Npc), L2MerchantInstance(L2NpcInstance), L2WarehouseInstance(L2NpcInstance), L2StaticObjectInstance(L2Character), L2DoorInstance(L2Character), L2NpcWalkerInstance(L2Npc), L2TerrainObjectInstance(L2Npc), L2EffectPointInstance(L2Npc), // Summons, Pets, Decoys and Traps L2ServitorInstance(L2Summon), L2SiegeSummonInstance(L2ServitorInstance), L2MerchantSummonInstance(L2ServitorInstance), L2PetInstance(L2Summon), L2BabyPetInstance(L2PetInstance), L2DecoyInstance(L2Decoy), L2TrapInstance(L2Trap), // Attackable L2Attackable(L2Npc), L2GuardInstance(L2Attackable), L2QuestGuardInstance(L2GuardInstance), L2MonsterInstance(L2Attackable), L2ChestInstance(L2MonsterInstance), L2ControllableMobInstance(L2MonsterInstance), L2FeedableBeastInstance(L2MonsterInstance), L2TamedBeastInstance(L2FeedableBeastInstance), L2FriendlyMobInstance(L2Attackable), L2PenaltyMonsterInstance(L2MonsterInstance), L2RiftInvaderInstance(L2MonsterInstance), L2RaidBossInstance(L2MonsterInstance), L2GrandBossInstance(L2RaidBossInstance), // FlyMobs L2FlyNpcInstance(L2NpcInstance), L2FlyMonsterInstance(L2MonsterInstance), L2FlyRaidBossInstance(L2RaidBossInstance), L2FlyTerrainObjectInstance(L2Npc), // Sepulchers L2SepulcherNpcInstance(L2NpcInstance), L2SepulcherMonsterInstance(L2MonsterInstance), // Festival L2FestivalGiudeInstance(L2Npc), L2FestivalMonsterInstance(L2MonsterInstance), // Vehicles L2Vehicle(L2Character), L2BoatInstance(L2Vehicle), L2AirShipInstance(L2Vehicle), L2ControllableAirShipInstance(L2AirShipInstance), // Siege L2DefenderInstance(L2Attackable), L2ArtefactInstance(L2NpcInstance), L2ControlTowerInstance(L2Npc), L2FlameTowerInstance(L2Npc), L2SiegeFlagInstance(L2Npc), L2SiegeNpcInstance(L2Npc), // Fort Siege L2FortBallistaInstance(L2Npc), L2FortCommanderInstance(L2DefenderInstance), // Castle NPCs L2CastleBlacksmithInstance(L2NpcInstance), L2CastleChamberlainInstance(L2MerchantInstance), L2CastleMagicianInstance(L2NpcInstance), L2CastleTeleporterInstance(L2Npc), L2CastleWarehouseInstance(L2WarehouseInstance), L2MercManagerInstance(L2MerchantInstance), // Fort NPCs L2FortEnvoyInstance(L2Npc), L2FortLogisticsInstance(L2MerchantInstance), L2FortManagerInstance(L2MerchantInstance), L2FortSiegeNpcInstance(L2NpcWalkerInstance), L2FortSupportCaptainInstance(L2MerchantInstance), // Seven Signs L2SignsPriestInstance(L2Npc), L2DawnPriestInstance(L2SignsPriestInstance), L2DuskPriestInstance(L2SignsPriestInstance), L2DungeonGatekeeperInstance(L2Npc), // City NPCs L2AdventurerInstance(L2NpcInstance), L2AuctioneerInstance(L2Npc), L2ClanHallManagerInstance(L2MerchantInstance), L2ClanTraderInstance(L2Npc), L2FameManagerInstance(L2Npc), L2FishermanInstance(L2MerchantInstance), L2ManorManagerInstance(L2MerchantInstance), L2MercenaryManagerInstance(L2Npc), L2ObservationInstance(L2Npc), L2OlympiadManagerInstance(L2Npc), L2PetManagerInstance(L2MerchantInstance), L2RaceManagerInstance(L2Npc), L2SymbolMakerInstance(L2Npc), L2TeleporterInstance(L2Npc), L2TownPetInstance(L2Npc), L2TrainerInstance(L2NpcInstance), L2TrainerHealersInstance(L2TrainerInstance), L2TransformManagerInstance(L2MerchantInstance), L2VillageMasterInstance(L2NpcInstance), L2WyvernManagerInstance(L2NpcInstance), // Doormens L2DoormenInstance(L2NpcInstance), L2CastleDoormenInstance(L2DoormenInstance), L2FortDoormenInstance(L2DoormenInstance), L2ClanHallDoormenInstance(L2DoormenInstance), // Custom L2ClassMasterInstance(L2NpcInstance), L2NpcBufferInstance(L2Npc), L2TvTEventNpcInstance(L2Npc), L2WeddingManagerInstance(L2Npc), L2EventMobInstance(L2Npc); private final InstanceType _parent; private final long _typeL; private final long _typeH; private final long _maskL; private final long _maskH; private InstanceType(InstanceType parent) { _parent = parent; final int high = ordinal() - (Long.SIZE - 1); if (high < 0) { _typeL = 1L << ordinal(); _typeH = 0; } else { _typeL = 0; _typeH = 1L << high; } if ((_typeL < 0) || (_typeH < 0)) { throw new Error("Too many instance types, failed to load " + name()); } if (parent != null) { _maskL = _typeL | parent._maskL; _maskH = _typeH | parent._maskH; } else { _maskL = _typeL; _maskH = _typeH; } } public final InstanceType getParent() { return _parent; } public final boolean isType(InstanceType it) { return ((_maskL & it._typeL) > 0) || ((_maskH & it._typeH) > 0); } public final boolean isTypes(InstanceType... it) { for (InstanceType i : it) { if (isType(i)) { return true; } } return false; } } protected final void setInstanceType(InstanceType i) { _instanceType = i; } public final InstanceType getInstanceType() { return _instanceType; } public final boolean isInstanceType(InstanceType i) { return _instanceType.isType(i); } public final boolean isInstanceTypes(InstanceType... i) { return _instanceType.isTypes(i); } public final void onAction(L2PcInstance player) { onAction(player, true); } public void onAction(L2PcInstance player, boolean interact) { IActionHandler handler = ActionHandler.getInstance().getHandler(getInstanceType()); if (handler != null) { handler.action(player, this, interact); } player.sendPacket(ActionFailed.STATIC_PACKET); } public void onActionShift(L2PcInstance player) { IActionHandler handler = ActionShiftHandler.getInstance().getHandler(getInstanceType()); if (handler != null) { handler.action(player, this, true); } player.sendPacket(ActionFailed.STATIC_PACKET); } public void onForcedAttack(L2PcInstance player) { player.sendPacket(ActionFailed.STATIC_PACKET); } /** * Do Nothing.
    *
    * Overridden in :
    *
    *
  • L2GuardInstance : Set the home location of its L2GuardInstance
  • L2Attackable : Reset the Spoiled flag

  • *
    */ public void onSpawn() { } // Position - Should remove to fully move to L2ObjectPosition public final void setXYZ(int x, int y, int z) { getPosition().setXYZ(x, y, z); } public final void setXYZInvisible(int x, int y, int z) { getPosition().setXYZInvisible(x, y, z); } public final int getX() { assert (getPosition().getWorldRegion() != null) || _isVisible; return getPosition().getX(); } /** * @return The id of the instance zone the object is in - id 0 is global since everything like dropped items, mobs, players can be in a instanciated area, it must be in l2object */ public int getInstanceId() { return _instanceId; } /** * UnAfraid: TODO: Add listener here. * @param instanceId The id of the instance zone the object is in - id 0 is global */ public void setInstanceId(int instanceId) { if ((instanceId < 0) || (_instanceId == instanceId)) { return; } Instance oldI = InstanceManager.getInstance().getInstance(_instanceId); Instance newI = InstanceManager.getInstance().getInstance(instanceId); if (newI == null) { return; } if (isPlayer()) { L2PcInstance player = getActingPlayer(); if ((_instanceId > 0) && (oldI != null)) { oldI.removePlayer(getObjectId()); if (oldI.isShowTimer()) { int startTime = (int) ((System.currentTimeMillis() - oldI.getInstanceStartTime()) / 1000); int endTime = (int) ((oldI.getInstanceEndTime() - oldI.getInstanceStartTime()) / 1000); if (oldI.isTimerIncrease()) { sendPacket(new ExSendUIEvent(this, true, true, startTime, endTime, oldI.getTimerText())); } else { sendPacket(new ExSendUIEvent(this, true, false, endTime - startTime, 0, oldI.getTimerText())); } } } if (instanceId > 0) { newI.addPlayer(getObjectId()); if (newI.isShowTimer()) { int startTime = (int) ((System.currentTimeMillis() - newI.getInstanceStartTime()) / 1000); int endTime = (int) ((newI.getInstanceEndTime() - newI.getInstanceStartTime()) / 1000); if (newI.isTimerIncrease()) { sendPacket(new ExSendUIEvent(this, false, true, startTime, endTime, newI.getTimerText())); } else { sendPacket(new ExSendUIEvent(this, false, false, endTime - startTime, 0, newI.getTimerText())); } } } if (player.hasSummon()) { player.getSummon().setInstanceId(instanceId); } } else if (isNpc()) { L2Npc npc = (L2Npc) this; if ((_instanceId > 0) && (oldI != null)) { oldI.removeNpc(npc); } if (instanceId > 0) { newI.addNpc(npc); } } _instanceId = instanceId; // If we change it for visible objects, me must clear & revalidates knownlists if (_isVisible && (_knownList != null)) { if (isPlayer()) { // We don't want some ugly looking disappear/appear effects, so don't update // the knownlist here, but players usually enter instancezones through teleporting // and the teleport will do the revalidation for us. } else { decayMe(); spawnMe(); } } } public final int getY() { assert (getPosition().getWorldRegion() != null) || _isVisible; return getPosition().getY(); } public final int getZ() { assert (getPosition().getWorldRegion() != null) || _isVisible; return getPosition().getZ(); } /** * Remove a L2Object from the world.
    *
    * Actions :
    *
    *
  • Remove the L2Object from the world

  • *
    * Caution : This method DOESN'T REMOVE the object from _allObjects of L2World
    * Caution : This method DOESN'T SEND Server->Client packets to players
    *
    * Assert :
    *
    *
  • _worldRegion != null (L2Object is visible at the beginning)

  • *
    * Example of use :
    *
    *
  • Delete NPC/PC or Unsummon

  • *
    */ public void decayMe() { assert getPosition().getWorldRegion() != null; L2WorldRegion reg = getPosition().getWorldRegion(); synchronized (this) { _isVisible = false; getPosition().setWorldRegion(null); } // this can synchronize on others instances, so it's out of // synchronized, to avoid deadlocks // Remove the L2Object from the world L2World.getInstance().removeVisibleObject(this, reg); L2World.getInstance().removeObject(this); } public void refreshID() { L2World.getInstance().removeObject(this); IdFactory.getInstance().releaseId(getObjectId()); _objectId = IdFactory.getInstance().getNextId(); } /** * Init the position of a L2Object spawn and add it in the world as a visible object.
    *
    * Actions :
    *
    *
  • Set the x,y,z position of the L2Object spawn and update its _worldregion
  • Add the L2Object spawn in the _allobjects of L2World
  • Add the L2Object spawn to _visibleObjects of its L2WorldRegion
  • Add the L2Object spawn in the world as a visible object

  • *
    * Assert :
    *
    *
  • _worldRegion == null (L2Object is invisible at the beginning)

  • *
    * Example of use :
    *
    *
  • Create Door
  • Spawn : Monster, Minion, CTs, Summon...

  • */ public final void spawnMe() { assert (getPosition().getWorldRegion() == null) && (getPosition().getWorldPosition().getX() != 0) && (getPosition().getWorldPosition().getY() != 0) && (getPosition().getWorldPosition().getZ() != 0); synchronized (this) { // Set the x,y,z position of the L2Object spawn and update its _worldregion _isVisible = true; getPosition().setWorldRegion(L2World.getInstance().getRegion(getPosition().getWorldPosition())); // Add the L2Object spawn in the _allobjects of L2World L2World.getInstance().storeObject(this); // Add the L2Object spawn to _visibleObjects and if necessary to _allplayers of its L2WorldRegion getPosition().getWorldRegion().addVisibleObject(this); } // this can synchronize on others instances, so it's out of // synchronized, to avoid deadlocks // Add the L2Object spawn in the world as a visible object L2World.getInstance().addVisibleObject(this, getPosition().getWorldRegion()); onSpawn(); } public final void spawnMe(int x, int y, int z) { assert getPosition().getWorldRegion() == null; synchronized (this) { // Set the x,y,z position of the L2Object spawn and update its _worldregion _isVisible = true; if (x > L2World.MAP_MAX_X) { x = L2World.MAP_MAX_X - 5000; } if (x < L2World.MAP_MIN_X) { x = L2World.MAP_MIN_X + 5000; } if (y > L2World.MAP_MAX_Y) { y = L2World.MAP_MAX_Y - 5000; } if (y < L2World.MAP_MIN_Y) { y = L2World.MAP_MIN_Y + 5000; } getPosition().setWorldPosition(x, y, z); getPosition().setWorldRegion(L2World.getInstance().getRegion(getPosition().getWorldPosition())); // Add the L2Object spawn in the _allobjects of L2World } L2World.getInstance().storeObject(this); // these can synchronize on others instances, so they're out of // synchronized, to avoid deadlocks // Add the L2Object spawn to _visibleObjects and if necessary to _allplayers of its L2WorldRegion getPosition().getWorldRegion().addVisibleObject(this); // Add the L2Object spawn in the world as a visible object L2World.getInstance().addVisibleObject(this, getPosition().getWorldRegion()); onSpawn(); } public void toggleVisible() { if (isVisible()) { decayMe(); } else { spawnMe(); } } public boolean isAttackable() { return false; } public abstract boolean isAutoAttackable(L2Character attacker); public boolean isMarker() { return false; } /** * Return the visibility state of the L2Object. Concept :
    *
    * A L2Object is visible if __IsVisible=true and _worldregion!=null
    *
    * @return */ public final boolean isVisible() { return getPosition().getWorldRegion() != null; } public final void setIsVisible(boolean value) { _isVisible = value; if (!_isVisible) { getPosition().setWorldRegion(null); } } public ObjectKnownList getKnownList() { return _knownList; } /** * Initializes the KnownList of the L2Object, is overwritten in classes that require a different knownlist Type. Removes the need for instanceof checks. */ public void initKnownList() { _knownList = new ObjectKnownList(this); } public final void setKnownList(ObjectKnownList value) { _knownList = value; } public final String getName() { return _name; } public void setName(String value) { _name = value; } public final int getObjectId() { return _objectId; } public final ObjectPoly getPoly() { if (_poly == null) { _poly = new ObjectPoly(this); } return _poly; } public ObjectPosition getPosition() { return _position; } /** * Initializes the Position class of the L2Object, is overwritten in classes that require a different position Type. Removes the need for instanceof checks. */ public void initPosition() { _position = new ObjectPosition(this); } public final void setObjectPosition(ObjectPosition value) { _position = value; } /** * @return reference to region this object is in. */ public L2WorldRegion getWorldRegion() { return getPosition().getWorldRegion(); } public L2PcInstance getActingPlayer() { return null; } /** * Sends the Server->Client info packet for the object.
    *
    * Is Overridden in:
  • L2AirShipInstance
  • L2BoatInstance
  • L2DoorInstance
  • L2PcInstance
  • L2StaticObjectInstance
  • L2Decoy
  • L2Npc
  • L2Summon
  • L2Trap
  • L2ItemInstance
  • * @param activeChar */ public void sendInfo(L2PcInstance activeChar) { } @Override public String toString() { return (getClass().getSimpleName() + ":" + getName() + "[" + getObjectId() + "]"); } /** * Not Implemented.
    *
    * Overridden in :
    *
    *
  • L2PcInstance

  • *
    * @param mov */ public void sendPacket(L2GameServerPacket mov) { // default implementation } /** * Not Implemented.
    *
    * Overridden in :
    *
    *
  • L2PcInstance

  • *
    * @param id */ public void sendPacket(SystemMessageId id) { // default implementation } /** * @return {@code true} if object is instance of L2PcInstance */ public boolean isPlayer() { return false; } /** * @return {@code true} if object is instance of L2Playable */ public boolean isPlayable() { return false; } /** * @return {@code true} if object is instance of L2Summon */ public boolean isSummon() { return false; } /** * @return {@code true} if object is instance of L2PetInstance */ public boolean isPet() { return false; } /** * @return {@code true} if object is instance of L2ServitorInstance */ public boolean isServitor() { return false; } /** * @return {@code true} if object is instance of L2DoorInstance */ public boolean isDoor() { return false; } /** * @return {@code true} if object is instance of L2Npc */ public boolean isNpc() { return false; } /** * @return {@code true} if object is instance of L2Attackable */ public boolean isL2Attackable() { return false; } /** * @return {@code true} if object is instance of L2MonsterInstance */ public boolean isMonster() { return false; } /** * @return {@code true} if object is instance of L2TrapInstance */ public boolean isTrap() { return false; } /** * @return {@code true} if object is instance of L2ItemInstance */ public boolean isItem() { return false; } /** * @return {@code true} if object Npc Walker or Vehicle */ public boolean isWalker() { return false; } /** * @return {@code true} if object Can be targeted */ public boolean isTargetable() { return true; } /** * Check if the object is in the given zone Id. * @param zone the zone Id to check * @return {@code true} if the object is in that zone Id */ public boolean isInsideZone(ZoneId zone) { return false; } /** * Check if current object has charged shot. * @param type of the shot to be checked. * @return {@code true} if the object has charged shot */ public boolean isChargedShot(ShotType type) { return false; } /** * Charging shot into the current object. * @param type of the shot to be charged. * @param charged */ public void setChargedShot(ShotType type, boolean charged) { } /** * Try to recharge a shot. * @param physical skill are using Soul shots. * @param magical skill are using Spirit shots. */ public void rechargeShots(boolean physical, boolean magical) { } }