Java tutorial
/* * 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 <http://www.gnu.org/licenses/>. */ package com.l2jfree.gameserver.model.zone; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.StringTokenizer; import javolution.util.FastMap; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Node; import com.l2jfree.Config; import com.l2jfree.gameserver.datatables.SkillTable; import com.l2jfree.gameserver.gameobjects.L2Creature; import com.l2jfree.gameserver.gameobjects.L2Npc; import com.l2jfree.gameserver.gameobjects.L2Object; import com.l2jfree.gameserver.gameobjects.L2Playable; import com.l2jfree.gameserver.gameobjects.L2Player; import com.l2jfree.gameserver.gameobjects.L2Summon; import com.l2jfree.gameserver.instancemanager.InstanceManager; import com.l2jfree.gameserver.model.Location; import com.l2jfree.gameserver.model.entity.Instance; import com.l2jfree.gameserver.model.quest.Quest; import com.l2jfree.gameserver.model.skills.L2Skill; import com.l2jfree.gameserver.model.skills.funcs.Func; import com.l2jfree.gameserver.model.skills.funcs.FuncOwner; import com.l2jfree.gameserver.model.zone.form.Shape; import com.l2jfree.gameserver.network.SystemMessageId; import com.l2jfree.gameserver.network.packets.L2ServerPacket; import com.l2jfree.gameserver.network.packets.server.SystemMessage; import com.l2jfree.tools.random.Rnd; import com.l2jfree.util.L2Collections; public class L2Zone implements FuncOwner { protected static final Log _log = LogFactory.getLog(L2Zone.class); public static enum ZoneType { Arena, Boss, Castle, CastleTeleport, Clanhall, CoreBarrier, Damage, Danger, Dynamic, Default, DefenderSpawn, Fishing, Fort, HeadQuarters, Jail, Mothertree, NoHQ, Pagan, Regeneration, Siege, SiegeDanger, Stadium, Town, Water, Script; private String getZoneClassName() { switch (this) { case Default: return "L2Zone"; default: return "L2" + name() + "Zone"; } } } // Overridden by siege zones, jail zone and town zones public static enum PvpSettings { GENERAL, ARENA, PEACE } public static enum RestartType { CHAOTIC, OWNER // Others are handled by mapregion manager } public static enum Affected { PLAYABLE, PC, NPC, ALL } public static enum Boss { ANAKIM, ANTHARAS, BAIUM, BAYLOR, FOURSEPULCHERS, FRINTEZZA, LASTIMPERIALTOMB, LILITH, SAILREN, SUNLIGHTROOM, VALAKAS, VANHALTER, ZAKEN } public static final byte FLAG_PVP = 0; public static final byte FLAG_PEACE = 1; public static final byte FLAG_SIEGE = 2; public static final byte FLAG_MOTHERTREE = 3; public static final byte FLAG_CLANHALL = 4; public static final byte FLAG_NOESCAPE = 5; public static final byte FLAG_NOWYVERN = 6; public static final byte FLAG_NOSTORE = 7; public static final byte FLAG_WATER = 8; public static final byte FLAG_FISHING = 9; public static final byte FLAG_JAIL = 10; public static final byte FLAG_STADIUM = 11; public static final byte FLAG_SUNLIGHTROOM = 12; public static final byte FLAG_DANGER = 13; public static final byte FLAG_CASTLE = 14; public static final byte FLAG_NOSUMMON = 15; public static final byte FLAG_FORT = 16; public static final byte FLAG_NOHEAL = 17; public static final byte FLAG_LANDING = 18; public static final byte FLAG_TOWN = 19; public static final byte FLAG_SCRIPT = 20; public static final byte FLAG_NO_HQ = 21; public static final byte FLAG_SIZE = 22; /** * Move speed multiplier applied when character is in water (swimming).<BR> * Tested on CT1 and CT1.5 NA retail */ public static final double WATER_MOVE_SPEED_BONUS = 0.55; private int _id; private String _name; private ZoneType _type; private boolean _enabled; private Shape[] _shapes; private Shape[] _exShapes; private final Location[][] _restarts = new Location[RestartType.values().length][]; private Quest[][] _questEvents; private int _castleId; private int _clanhallId; private int _townId; private int _fortId; private PvpSettings _pvp; private Boss _boss; private Affected _affected = Affected.ALL; /** Can't logout (including back to character selection menu); can't use SoE? */ private boolean _noEscape; /** Can't use wyvern */ private boolean _noWyvern; /** Fly transform zone (gracia) */ private boolean _landing; private boolean _noPrivateStore; private boolean _noSummon; /** Can't cast heal if caster is in zone; can't receive healing if target is in zone */ private boolean _noHeal; private SystemMessage _onEnterMsg; private SystemMessage _onExitMsg; private int _abnormal; private int _hpDamage; private int _mpDamage; private boolean _exitOnDeath; private boolean _buffRepeat; // Used for buffs and debuffs protected L2Skill[] _applyEnter; private L2Skill[] _applyExit; private int[] _removeEnter; protected int[] _removeExit; // Instances private String _instanceName; private String _instanceGroup; private int _minPlayers; private int _maxPlayers; // Quests private int _uniqueId; private Func[] _statFuncs; protected final void addStatFunc(Func func) { if (_statFuncs == null) _statFuncs = new Func[] { func }; else _statFuncs = ArrayUtils.add(_statFuncs, func); } protected void register() throws Exception { } public final int getId() { return _id; } public final String getName() { return _name; } public final ZoneType getType() { return _type; } public final String getClassName() { return getClass().getSimpleName(); } public final int getCastleId() { return _castleId; } public final int getTownId() { return _townId; } public final int getClanhallId() { return _clanhallId; } public final int getFortId() { return _fortId; } public final Boss getBoss() { return _boss; } /** * <B>Get HP damage over time</B> (<I>per cycle</I>)<BR><BR> * <U>The interval is not necessarily one second</U>. * Default interval is 3000 ms. * @return HP amount to be subtracted * @see #getMPDamagePerSecond() */ public final int getHPDamagePerSecond() { return _hpDamage; } /** * <B>Get MP damage over time</B> (<I>per cycle</I>)<BR><BR> * <U>The interval is not necessarily one second</U>. * Default interval is 3000 ms. * @return HP amount to be subtracted * @see #getHPDamagePerSecond() */ public final int getMPDamagePerSecond() { return _mpDamage; } public final boolean isRepeatingBuff() { return _buffRepeat; } public final boolean isPeace() { return _pvp == PvpSettings.PEACE; } public final boolean isEnabled() { return _enabled; } public final void setEnabled(boolean val) { _enabled = val; } public final Location getRestartPoint(RestartType type) { Location[] points = _restarts[type.ordinal()]; if (points != null && points.length != 0) return points[Rnd.get(points.length)]; // No restartpoint defined return null; } protected final L2Skill[] getApplyEnter() { return _applyEnter; } protected final int[] getRemoveEnter() { return _removeEnter; } private final FastMap<L2Creature, Boolean> _charactersInside = new FastMap<L2Creature, Boolean>() .setShared(true); protected final FastMap<L2Creature, Boolean> getCharactersInsideMap() { return _charactersInside; } public final Set<L2Creature> getCharactersInside() { return _charactersInside.keySet(); } public final Iterable<L2Creature> getCharactersInsideActivated() { return L2Collections.convertingIterable(_charactersInside.entrySet(), new L2Collections.Converter<Map.Entry<L2Creature, Boolean>, L2Creature>() { @Override public L2Creature convert(Entry<L2Creature, Boolean> src) { if (Boolean.TRUE.equals(src.getValue())) return src.getKey(); return null; } }); } /** * Check default never changing conditions. Determines zone can be activated on player or not at all. */ protected boolean checkConstantConditions(L2Creature character) { return isCorrectType(character); } /** * Check conditions that can be changed anytime. Determines zone can be activated or not on the player currently. */ protected boolean checkDynamicConditions(L2Creature character) { if (_exitOnDeath && character.isDead()) return false; return isEnabled(); } private State getExpectedState(L2Creature character) { if (character instanceof L2Player) { if (((L2Player) character).getOnlineState() == L2Player.ONLINE_STATE_DELETED) { _log.warn("", new IllegalStateException()); return State.OUTSIDE; } } if (!isInsideZone(character)) return State.OUTSIDE; if (!checkConstantConditions(character)) return State.INSIDE_BUT_NOT_ACTIVED; if (!checkDynamicConditions(character)) return State.INSIDE_BUT_NOT_ACTIVED; return State.INSIDE_AND_ACTIVATED; } private State getCurrentState(L2Creature character) { final Boolean isActive = _charactersInside.get(character); if (isActive == null) return State.OUTSIDE; return isActive ? State.INSIDE_AND_ACTIVATED : State.INSIDE_BUT_NOT_ACTIVED; } private enum State { OUTSIDE, INSIDE_BUT_NOT_ACTIVED, INSIDE_AND_ACTIVATED; } public final void revalidateAllInZone() { for (L2Creature character : getCharactersInside()) revalidateInZone(character); } public final void revalidateInZone(L2Creature character) { changeStateOf(character, getExpectedState(character)); } private void changeStateOf(L2Creature character, State expectedState) { final State currentState = getCurrentState(character); if (currentState == expectedState) return; switch (expectedState) { case INSIDE_AND_ACTIVATED: { _charactersInside.put(character, Boolean.TRUE); onEnter(character); break; } case INSIDE_BUT_NOT_ACTIVED: { _charactersInside.put(character, Boolean.FALSE); if (currentState == State.INSIDE_AND_ACTIVATED) onExit(character); break; } case OUTSIDE: { _charactersInside.remove(character); if (currentState == State.INSIDE_AND_ACTIVATED) onExit(character); break; } } } protected void onEnter(L2Creature character) { final L2Player player = character instanceof L2Player ? (L2Player) character : null; Quest[] quests = getQuestByEvent(Quest.QuestEventType.ON_ENTER_ZONE); if (quests != null) { for (Quest quest : quests) { quest.notifyEnterZone(character, this); } } if (player != null && _onEnterMsg != null) player.sendPacket(_onEnterMsg); if (_abnormal > 0) character.startAbnormalEffect(_abnormal); if (_applyEnter != null) for (L2Skill sk : _applyEnter) sk.getEffects(character, character); if (_removeEnter != null) for (int id : _removeEnter) character.stopSkillEffects(id); if (_statFuncs != null) character.addStatFuncs(_statFuncs); if (_pvp == PvpSettings.ARENA) { character.setInsideZone(FLAG_NOSUMMON, true); character.setInsideZone(FLAG_PVP, true); } else if (_pvp == PvpSettings.PEACE) { if (Config.ZONE_TOWN != 2) character.setInsideZone(FLAG_PEACE, true); } if (_noWyvern && player != null) { character.setInsideZone(FLAG_NOWYVERN, true); if (player.getMountType() == 2) player.enteredNoWyvernZone(); } if (_noEscape) character.setInsideZone(FLAG_NOESCAPE, true); if (_noPrivateStore) character.setInsideZone(FLAG_NOSTORE, true); if (_noSummon) character.setInsideZone(FLAG_NOSUMMON, true); if (_noHeal) character.setInsideZone(FLAG_NOHEAL, true); if (_landing) character.setInsideZone(FLAG_LANDING, true); if (_instanceName != null && _instanceGroup != null && player != null) tryPortIntoInstance(player); } protected void onExit(L2Creature character) { final L2Player player = character instanceof L2Player ? (L2Player) character : null; Quest[] quests = getQuestByEvent(Quest.QuestEventType.ON_EXIT_ZONE); if (quests != null) { for (Quest quest : quests) { quest.notifyExitZone(character, this); } } if (player != null && _onExitMsg != null) player.sendPacket(_onExitMsg); if (_abnormal > 0) character.stopAbnormalEffect(_abnormal); if (_applyExit != null) for (L2Skill sk : _applyExit) sk.getEffects(character, character); if (_removeExit != null) for (int id : _removeExit) character.stopSkillEffects(id); if (_statFuncs != null) character.removeStatsOwner(this); if (_pvp == PvpSettings.ARENA) { character.setInsideZone(FLAG_NOSUMMON, false); character.setInsideZone(FLAG_PVP, false); } else if (_pvp == PvpSettings.PEACE) { character.setInsideZone(FLAG_PEACE, false); } if (_noWyvern && player != null) { character.setInsideZone(FLAG_NOWYVERN, false); if (player.getMountType() == 2) player.exitedNoWyvernZone(); } if (_noEscape) character.setInsideZone(FLAG_NOESCAPE, false); if (_noPrivateStore) character.setInsideZone(FLAG_NOSTORE, false); if (_noSummon) character.setInsideZone(FLAG_NOSUMMON, false); if (_noHeal) character.setInsideZone(FLAG_NOHEAL, false); if (_landing) character.setInsideZone(FLAG_LANDING, false); if (_instanceName != null && player != null && player.isInInstance()) portIntoInstance(player, 0); } private static final int REASON_OK = 0; private static final int REASON_MULTIPLE_INSTANCE = 1; private static final int REASON_INSTANCE_FULL = 2; private static final int REASON_SMALL_GROUP = 3; private static final class InstanceResult { private int instanceId = 0; private int reason = REASON_OK; } private void tryPortIntoInstance(L2Player pl) { InstanceResult ir = new InstanceResult(); if (_instanceGroup.equals("party")) { if (pl.isInParty()) { List<L2Player> list = pl.getParty().getPartyMembers(); getInstanceFromGroup(ir, list, false); checkPlayersInside(ir, list); } } else if (_instanceGroup.equals("clan")) { if (pl.getClan() != null) { List<L2Player> list = pl.getClan().getOnlineMembersList(); getInstanceFromGroup(ir, list, true); checkPlayersInside(ir, list); } } else if (_instanceGroup.equals("alliance")) { if (pl.getAllyId() > 0) { List<L2Player> list = pl.getClan().getOnlineAllyMembers(); getInstanceFromGroup(ir, list, true); checkPlayersInside(ir, list); } } if (ir.reason == REASON_MULTIPLE_INSTANCE) { pl.sendMessage("You cannot enter this instance while other " + _instanceGroup + " members are in another instance."); } else if (ir.reason == REASON_INSTANCE_FULL) { pl.sendMessage("This instance is full. There is a maximum of " + _maxPlayers + " players inside."); } else if (ir.reason == REASON_SMALL_GROUP) { pl.sendMessage("Your " + _instanceGroup + " is too small. There is a minimum of " + _minPlayers + " players inside."); } else { try { if (ir.instanceId == 0) ir.instanceId = InstanceManager.getInstance().createDynamicInstance(_instanceName); portIntoInstance(pl, ir.instanceId); } catch (Exception e) { pl.sendMessage("The requested instance could not be created."); } } } private void getInstanceFromGroup(InstanceResult ir, List<L2Player> group, boolean allowMultiple) { for (L2Player mem : group) { if (mem == null || !mem.isInInstance()) continue; Instance i = InstanceManager.getInstance().getInstance(mem.getInstanceId()); if (i.getName().equals(_instanceName)) { ir.instanceId = i.getId(); // Player in this instance template found return; } else if (!allowMultiple) { ir.reason = REASON_MULTIPLE_INSTANCE; return; } } } private void checkPlayersInside(InstanceResult ir, List<L2Player> group) { if (ir.reason != REASON_OK) return; int valid = 0, all = 0; for (L2Player mem : group) { if (mem != null && mem.isSameInstance(ir.instanceId)) valid++; all++; if (valid == _maxPlayers) { ir.reason = REASON_INSTANCE_FULL; return; } } if (all < _minPlayers) { ir.reason = REASON_SMALL_GROUP; } } private void portIntoInstance(L2Player pl, int instanceId) { pl.setInstanceId(instanceId); pl.getKnownList().updateKnownObjects(); L2Summon pet = pl.getPet(); if (pet != null) pet.getKnownList().updateKnownObjects(); } public final void onDie(L2Creature character) { if (getCurrentState(character) == State.INSIDE_AND_ACTIVATED) onDieInside(character); // will exit the zone, if it's disabled because of "_exitOnDeath" revalidateInZone(character); } public final void onRevive(L2Creature character) { // will enter the zone, if it was disabled because of "_exitOnDeath" revalidateInZone(character); if (getCurrentState(character) == State.INSIDE_AND_ACTIVATED) onReviveInside(character); } protected void onDieInside(L2Creature character) { } protected void onReviveInside(L2Creature character) { } public final void removeFromZone(L2Creature character) { changeStateOf(character, State.OUTSIDE); } private boolean isCorrectType(L2Creature character) { switch (_affected) { case PLAYABLE: return character instanceof L2Playable; case PC: return character instanceof L2Player; case NPC: return character instanceof L2Npc; case ALL: return true; } return false; } /** * Checks if the given coordinates are within the zone * * @param x * @param y */ public final boolean isInsideZone(int x, int y) { if (_exShapes != null) for (Shape sh : _exShapes) if (sh.contains(x, y)) return false; for (Shape sh : _shapes) if (sh.contains(x, y)) return true; return false; } /** * Checks if the given coordinates are within the zone * * @param x * @param y * @param z */ public final boolean isInsideZone(int x, int y, int z) { if (_exShapes != null) for (Shape sh : _exShapes) if (sh.contains(x, y, z)) return false; for (Shape sh : _shapes) if (sh.contains(x, y, z)) return true; return false; } /** * Checks if the given obejct is inside the zone. * * @param object */ public final boolean isInsideZone(L2Object object) { return isInsideZone(object.getX(), object.getY(), object.getZ()); } public final double getDistanceToZone(L2Object object) { return getDistanceToZone(object.getX(), object.getY()); } public final double getDistanceToZone(int x, int y) { double dist = Double.MAX_VALUE; for (Shape sh : _shapes) dist = Math.min(dist, sh.getDistanceToZone(x, y)); return dist; } public final boolean isCloserThan(int x, int y, int distance) { for (Shape sh : _shapes) if (sh.isCloserThan(x, y, distance)) return true; return false; } public final int getMiddleX() { if (_shapes.length == 0) { _log.error(this + " has no shapes defined"); return 0; } int sum = 0; for (Shape sh : _shapes) sum += sh.getMiddleX(); return (sum / _shapes.length); } public final int getMiddleY() { if (_shapes.length == 0) { _log.error(this + " has no shapes defined"); return 0; } int sum = 0; for (Shape sh : _shapes) sum += sh.getMiddleY(); return (sum / _shapes.length); } public final boolean intersectsRectangle(int ax, int bx, int ay, int by) { for (Shape sh : _shapes) if (sh.intersectsRectangle(ax, bx, ay, by)) return true; return false; } public final int getMaxZ(L2Object obj) { return getMaxZ(obj.getX(), obj.getY(), obj.getZ()); } public final int getMinZ(L2Object obj) { return getMinZ(obj.getX(), obj.getY(), obj.getZ()); } public final int getMaxZ(int x, int y, int z) { for (Shape sh : _shapes) if (sh.contains(x, y)) return sh.getMaxZ(); return z; } public final int getMinZ(int x, int y, int z) { for (Shape sh : _shapes) if (sh.contains(x, y)) return sh.getMinZ(); return z; } public final Location getRandomLocation() { if (_shapes.length == 0) { _log.error(this + " has no shapes defined"); return Location.EMPTY_LOCATION; } return _shapes[Rnd.get(_shapes.length)].getRandomLocation(); } /** * Some GrandBosses send all players in zone to a specific part of the zone, rather than just removing them all. If * this is the case, this command should be used. * * @param x * @param y * @param z */ public final void movePlayersTo(int x, int y, int z) { for (L2Creature character : getCharactersInside()) if (character instanceof L2Player) character.teleToLocation(x, y, z); } @Override public final String toString() { return getClassName() + "[id='" + getId() + "',name='" + getName() + "']"; } @Override public final String getFuncOwnerName() { return getName(); } @Override public final L2Skill getFuncOwnerSkill() { return null; } public void addQuestEvent(Quest.QuestEventType EventType, Quest q) { if (_questEvents == null) _questEvents = new Quest[Quest.QuestEventType.values().length][]; Quest[] questByEvents = _questEvents[EventType.ordinal()]; if (questByEvents == null) questByEvents = new Quest[] { q }; else { if (!ArrayUtils.contains(questByEvents, q)) questByEvents = ArrayUtils.add(questByEvents, q); } _questEvents[EventType.ordinal()] = questByEvents; } public Quest[] getQuestByEvent(Quest.QuestEventType EventType) { if (_questEvents == null) return null; return _questEvents[EventType.ordinal()]; } /** * Returns a unique zone identifier, <U><B>if</B> it was specified</U> when * declaring the zone. Primarily used to obtain an unique zone for Quests.<BR> * Will return 0 for each zone which needn't to be unique. * @return an unique ID or 0 */ public int getQuestZoneId() { return _uniqueId; } /** * Broadcasts packet to all players inside the zone */ public void broadcastPacket(L2ServerPacket packet) { for (L2Creature character : getCharactersInside()) if (character instanceof L2Player) character.getActingPlayer().sendPacket(packet); } // Zone parser public static L2Zone parseZone(Node zn) { Integer id = -1; ZoneType type = null; String name; Boolean enabled; L2Zone zone = null; try { id = Integer.parseInt(zn.getAttributes().getNamedItem("id").getNodeValue()); Node tn = zn.getAttributes().getNamedItem("type"); Node nn = zn.getAttributes().getNamedItem("name"); Node en = zn.getAttributes().getNamedItem("enabled"); type = (tn != null) ? ZoneType.valueOf(tn.getNodeValue()) : ZoneType.Default; name = (nn != null) ? nn.getNodeValue() : id.toString(); enabled = (en != null) ? Boolean.parseBoolean(en.getNodeValue()) : true; Class<?> clazz = Class.forName("com.l2jfree.gameserver.model.zone." + type.getZoneClassName()); Constructor<?> constructor = clazz.getConstructor(); zone = (L2Zone) constructor.newInstance(); } catch (Exception e) { _log.error("Cannot create a L2" + type + "Zone for id " + id, e); return null; } zone._id = id; zone._type = type; zone._name = name; zone._enabled = enabled; List<Shape> shapes = new ArrayList<Shape>(); List<Shape> exShapes = new ArrayList<Shape>(); for (Node n = zn.getFirstChild(); n != null; n = n.getNextSibling()) { if ("shape".equalsIgnoreCase(n.getNodeName())) { Shape sh = Shape.parseShape(n, id); if (sh != null) { if (sh.isExclude()) exShapes.add(sh); else shapes.add(sh); } else return null; } else if ("entity".equalsIgnoreCase(n.getNodeName())) { try { zone.parseEntity(n); } catch (Exception e) { _log.error("Cannot parse entity for " + zone, e); return null; } } else if ("instance".equalsIgnoreCase(n.getNodeName())) { try { zone.parseInstance(n); } catch (Exception e) { _log.error("Cannot parse instance for " + zone, e); return null; } } else if ("settings".equalsIgnoreCase(n.getNodeName())) { try { zone.parseSettings(n); } catch (Exception e) { _log.error("Cannot parse settings for " + zone, e); return null; } } else if ("msg".equalsIgnoreCase(n.getNodeName())) { try { zone.parseMessages(n); } catch (Exception e) { _log.error("Cannot parse messages for " + zone, e); return null; } } else if ("skill".equalsIgnoreCase(n.getNodeName())) { try { zone.parseSkills(n); } catch (Exception e) { _log.error("Cannot parse skills for " + zone, e); return null; } } else if ("cond".equalsIgnoreCase(n.getNodeName())) { try { zone.parseCondition(n.getFirstChild()); } catch (Exception e) { _log.error("Cannot parse skills for " + zone, e); return null; } } else if ("restart_chaotic".equalsIgnoreCase(n.getNodeName())) { try { zone.parseRestart(n, RestartType.CHAOTIC); } catch (Exception e) { _log.error("Cannot parse chaotic restart point for " + zone, e); return null; } } else if ("restart_owner".equalsIgnoreCase(n.getNodeName())) { try { zone.parseRestart(n, RestartType.OWNER); } catch (Exception e) { _log.error("Cannot parse owner restart point for " + zone, e); return null; } } else if (n.getNodeType() == Node.ELEMENT_NODE) { _log.error("Cannot parse <" + n.getNodeName() + "> for " + zone); return null; } } zone._shapes = shapes.toArray(new Shape[shapes.size()]); if (!exShapes.isEmpty()) zone._exShapes = exShapes.toArray(new Shape[exShapes.size()]); try { zone.register(); } catch (Exception e) { _log.warn("Registration problem for " + zone, e); } return zone; } private void parseRestart(Node n, RestartType t) throws Exception { Node xn = n.getAttributes().getNamedItem("x"); Node yn = n.getAttributes().getNamedItem("y"); Node zn = n.getAttributes().getNamedItem("z"); int x = Integer.parseInt(xn.getNodeValue()); int y = Integer.parseInt(yn.getNodeValue()); int z = Integer.parseInt(zn.getNodeValue()); _restarts[t.ordinal()] = ArrayUtils.add(_restarts[t.ordinal()], new Location(x, y, z)); } private void parseEntity(Node n) throws Exception { Node castle = n.getAttributes().getNamedItem("castleId"); Node clanhall = n.getAttributes().getNamedItem("clanhallId"); Node town = n.getAttributes().getNamedItem("townId"); Node fort = n.getAttributes().getNamedItem("fortId"); _castleId = (castle != null) ? Integer.parseInt(castle.getNodeValue()) : -1; _clanhallId = (clanhall != null) ? Integer.parseInt(clanhall.getNodeValue()) : -1; _townId = (town != null) ? Integer.parseInt(town.getNodeValue()) : -1; _fortId = (fort != null) ? Integer.parseInt(fort.getNodeValue()) : -1; } private void parseInstance(Node n) throws Exception { Node instanceName = n.getAttributes().getNamedItem("instanceName"); Node instanceGroup = n.getAttributes().getNamedItem("instanceGroup"); Node minPlayers = n.getAttributes().getNamedItem("minPlayers"); Node maxPlayers = n.getAttributes().getNamedItem("maxPlayers"); _instanceName = (instanceName != null) ? instanceName.getNodeValue() : null; _instanceGroup = (instanceGroup != null) ? instanceGroup.getNodeValue().toLowerCase() : null; _minPlayers = (minPlayers != null) ? Integer.parseInt(minPlayers.getNodeValue()) : -1; _maxPlayers = (maxPlayers != null) ? Integer.parseInt(maxPlayers.getNodeValue()) : -1; } private void parseSettings(Node n) throws Exception { Node pvp = n.getAttributes().getNamedItem("pvp"); Node noWyvern = n.getAttributes().getNamedItem("noWyvern"); Node landing = n.getAttributes().getNamedItem("landing"); Node noEscape = n.getAttributes().getNamedItem("noEscape"); Node noPrivateStore = n.getAttributes().getNamedItem("noPrivateStore"); Node noSummon = n.getAttributes().getNamedItem("noSummon"); // Forbids summon friend skills. Node boss = n.getAttributes().getNamedItem("boss"); Node affected = n.getAttributes().getNamedItem("affected"); Node buffRepeat = n.getAttributes().getNamedItem("buffRepeat"); Node abnorm = n.getAttributes().getNamedItem("abnormal"); Node exitOnDeath = n.getAttributes().getNamedItem("exitOnDeath"); Node hpDamage = n.getAttributes().getNamedItem("hpDamage"); Node mpDamage = n.getAttributes().getNamedItem("mpDamage"); Node noHeal = n.getAttributes().getNamedItem("noHeal"); Node uniqueId = n.getAttributes().getNamedItem("questZoneId"); _pvp = (pvp != null) ? PvpSettings.valueOf(pvp.getNodeValue().toUpperCase()) : PvpSettings.GENERAL; _noWyvern = (noWyvern != null) && Boolean.parseBoolean(noWyvern.getNodeValue()); _landing = (landing != null) && Boolean.parseBoolean(landing.getNodeValue()); _noEscape = (noEscape != null) && Boolean.parseBoolean(noEscape.getNodeValue()); _noPrivateStore = (noPrivateStore != null) && Boolean.parseBoolean(noPrivateStore.getNodeValue()); _noSummon = (noSummon != null) && Boolean.parseBoolean(noSummon.getNodeValue()); _boss = (boss != null) ? Boss.valueOf(boss.getNodeValue().toUpperCase()) : null; _affected = (affected != null) ? Affected.valueOf(affected.getNodeValue().toUpperCase()) : Affected.PLAYABLE; _buffRepeat = (buffRepeat != null) && Boolean.parseBoolean(buffRepeat.getNodeValue()); _abnormal = (abnorm != null) ? Integer.decode("0x" + abnorm.getNodeValue()) : 0; _exitOnDeath = (exitOnDeath != null) && Boolean.parseBoolean(exitOnDeath.getNodeValue()); _hpDamage = (hpDamage != null) ? Integer.parseInt(hpDamage.getNodeValue()) : 0; _mpDamage = (mpDamage != null) ? Integer.parseInt(mpDamage.getNodeValue()) : 0; _noHeal = (noHeal != null) && Boolean.parseBoolean(noHeal.getNodeValue()); _uniqueId = (uniqueId != null) ? Integer.parseInt(uniqueId.getNodeValue()) : 0; } private void parseMessages(Node n) throws Exception { Node enter = n.getAttributes().getNamedItem("onEnter"); Node exit = n.getAttributes().getNamedItem("onExit"); if (enter != null) { String onEnter = enter.getNodeValue(); try { _onEnterMsg = SystemMessageId.getSystemMessageId(Integer.parseInt(onEnter), true) .getSystemMessage(); } catch (NumberFormatException nfe) { _onEnterMsg = SystemMessage.sendString(onEnter); } } if (exit != null) { String onExit = exit.getNodeValue(); try { _onExitMsg = SystemMessageId.getSystemMessageId(Integer.parseInt(onExit), true).getSystemMessage(); } catch (NumberFormatException nfe) { _onExitMsg = SystemMessage.sendString(onExit); } } } private void parseSkills(Node n) throws Exception { Node aen = n.getAttributes().getNamedItem("applyEnter"); Node aex = n.getAttributes().getNamedItem("applyExit"); Node ren = n.getAttributes().getNamedItem("removeEnter"); Node rex = n.getAttributes().getNamedItem("removeExit"); if (aen != null) _applyEnter = parseApplySkill(aen.getNodeValue()); if (aex != null) _applyExit = parseApplySkill(aex.getNodeValue()); if (ren != null) _removeEnter = parseRemoveSkill(ren.getNodeValue()); if (rex != null) _removeExit = parseRemoveSkill(rex.getNodeValue()); } private L2Skill[] parseApplySkill(String set) { L2Skill[] skills = null; StringTokenizer st = new StringTokenizer(set, ";"); while (st.hasMoreTokens()) { StringTokenizer st2 = new StringTokenizer(st.nextToken(), ","); int skillId = Integer.parseInt(st2.nextToken()); int level = Integer.parseInt(st2.nextToken()); L2Skill skill = SkillTable.getInstance().getInfo(skillId, level); if (skill != null) { if (skills == null) skills = new L2Skill[] { skill }; else skills = ArrayUtils.add(skills, skill); } } return skills; } private int[] parseRemoveSkill(String set) { int[] skillIds = null; StringTokenizer st = new StringTokenizer(set, ";"); while (st.hasMoreTokens()) { int skillId = Integer.parseInt(st.nextToken()); skillIds = ArrayUtils.add(skillIds, skillId); } return skillIds; } protected void parseCondition(Node n) throws Exception { throw new IllegalStateException("This zone shouldn't have conditions!"); } }