/* * 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.model.actor.templates; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import com.l2jserver.Config; import com.l2jserver.gameserver.data.xml.impl.NpcData; import com.l2jserver.gameserver.enums.AISkillScope; import com.l2jserver.gameserver.enums.AIType; import com.l2jserver.gameserver.enums.Race; import com.l2jserver.gameserver.enums.Sex; import com.l2jserver.gameserver.model.StatsSet; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.base.ClassId; import com.l2jserver.gameserver.model.drops.DropListScope; import com.l2jserver.gameserver.model.drops.IDropItem; import com.l2jserver.gameserver.model.holders.ItemHolder; import com.l2jserver.gameserver.model.interfaces.IIdentifiable; import com.l2jserver.gameserver.model.skills.Skill; /** * NPC template. * @author NosBit */ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable { private int _id; private int _displayId; private byte _level; private String _type; private String _name; private boolean _usingServerSideName; private String _title; private boolean _usingServerSideTitle; private StatsSet _parameters; private Sex _sex; private int _chestId; private int _rhandId; private int _lhandId; private int _weaponEnchant; private double _exp; private double _sp; private double _raidPoints; private boolean _unique; private boolean _attackable; private boolean _targetable; private boolean _talkable; private boolean _undying; private boolean _showName; private boolean _flying; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; private boolean _hasSummoner; private boolean _canBeSown; private int _corpseTime; private AIType _aiType; private int _aggroRange; private int _clanHelpRange; private int _dodge; private boolean _isChaos; private boolean _isAggressive; private int _soulShot; private int _spiritShot; private int _soulShotChance; private int _spiritShotChance; private int _minSkillChance; private int _maxSkillChance; private int _primarySkillId; private int _shortRangeSkillId; private int _shortRangeSkillChance; private int _longRangeSkillId; private int _longRangeSkillChance; private Map<Integer, Skill> _skills; private Map<AISkillScope, List<Skill>> _aiSkillLists; private Set<Integer> _clans; private Set<Integer> _ignoreClanNpcIds; private Map<DropListScope, List<IDropItem>> _dropLists; private double _collisionRadiusGrown; private double _collisionHeightGrown; private final List<ClassId> _teachInfo = new ArrayList<>(); /** * Constructor of L2Character. * @param set The StatsSet object to transfer data to the method */ public L2NpcTemplate(StatsSet set) { super(set); } @Override public void set(StatsSet set) { super.set(set); _id = set.getInt("id"); _displayId = set.getInt("displayId", _id); _level = set.getByte("level", (byte) 70); _type = set.getString("type", "L2Npc"); _name = set.getString("name", ""); _usingServerSideName = set.getBoolean("usingServerSideName", false); _title = set.getString("title", ""); _usingServerSideTitle = set.getBoolean("usingServerSideTitle", false); setRace(set.getEnum("race", Race.class, Race.NONE)); _sex = set.getEnum("sex", Sex.class, Sex.ETC); _chestId = set.getInt("chestId", 0); _rhandId = set.getInt("rhandId", 0); _lhandId = set.getInt("lhandId", 0); _weaponEnchant = set.getInt("weaponEnchant", 0); _exp = set.getDouble("exp", 0); _sp = set.getDouble("sp", 0); _raidPoints = set.getDouble("raidPoints", 0); _unique = set.getBoolean("unique", false); _attackable = set.getBoolean("attackable", true); _targetable = set.getBoolean("targetable", true); _talkable = set.getBoolean("talkable", true); _undying = set.getBoolean("undying", true); _showName = set.getBoolean("showName", true); _flying = set.getBoolean("flying", false); _canMove = set.getBoolean("canMove", true); _noSleepMode = set.getBoolean("noSleepMode", false); _passableDoor = set.getBoolean("passableDoor", false); _hasSummoner = set.getBoolean("hasSummoner", false); _canBeSown = set.getBoolean("canBeSown", false); _corpseTime = set.getInt("corpseTime", Config.DEFAULT_CORPSE_TIME); _aiType = set.getEnum("aiType", AIType.class, AIType.FIGHTER); _aggroRange = set.getInt("aggroRange", 0); _clanHelpRange = set.getInt("clanHelpRange", 0); _dodge = set.getInt("dodge", 0); _isChaos = set.getBoolean("isChaos", false); _isAggressive = set.getBoolean("isAggressive", true); _soulShot = set.getInt("soulShot", 0); _spiritShot = set.getInt("spiritShot", 0); _soulShotChance = set.getInt("shotShotChance", 0); _spiritShotChance = set.getInt("spiritShotChance", 0); _minSkillChance = set.getInt("minSkillChance", 7); _maxSkillChance = set.getInt("maxSkillChance", 15); _primarySkillId = set.getInt("primarySkillId", 0); _shortRangeSkillId = set.getInt("shortRangeSkillId", 0); _shortRangeSkillChance = set.getInt("shortRangeSkillChance", 0); _longRangeSkillId = set.getInt("longRangeSkillId", 0); _longRangeSkillChance = set.getInt("longRangeSkillChance", 0); _collisionRadiusGrown = set.getDouble("collisionRadiusGrown", 0); _collisionHeightGrown = set.getDouble("collisionHeightGrown", 0); } @Override public int getId() { return _id; } public int getDisplayId() { return _displayId; } public byte getLevel() { return _level; } public String getType() { return _type; } public boolean isType(String type) { return getType().equalsIgnoreCase(type); } public String getName() { return _name; } public boolean isUsingServerSideName() { return _usingServerSideName; } public String getTitle() { return _title; } public boolean isUsingServerSideTitle() { return _usingServerSideTitle; } public StatsSet getParameters() { return _parameters; } public void setParameters(StatsSet set) { _parameters = set; } public Sex getSex() { return _sex; } public int getChestId() { return _chestId; } public int getRHandId() { return _rhandId; } public int getLHandId() { return _lhandId; } public int getWeaponEnchant() { return _weaponEnchant; } public double getExp() { return _exp; } public double getSP() { return _sp; } public double getRaidPoints() { return _raidPoints; } public boolean isUnique() { return _unique; } public boolean isAttackable() { return _attackable; } public boolean isTargetable() { return _targetable; } public boolean isTalkable() { return _talkable; } public boolean isUndying() { return _undying; } public boolean isShowName() { return _showName; } public boolean isFlying() { return _flying; } public boolean canMove() { return _canMove; } public boolean isNoSleepMode() { return _noSleepMode; } public boolean isPassableDoor() { return _passableDoor; } public boolean hasSummoner() { return _hasSummoner; } public boolean canBeSown() { return _canBeSown; } public int getCorpseTime() { return _corpseTime; } public AIType getAIType() { return _aiType; } public int getAggroRange() { return _aggroRange; } public int getClanHelpRange() { return _clanHelpRange; } public int getDodge() { return _dodge; } public boolean isChaos() { return _isChaos; } public boolean isAggressive() { return _isAggressive; } public int getSoulShot() { return _soulShot; } public int getSpiritShot() { return _spiritShot; } public int getSoulShotChance() { return _soulShotChance; } public int getSpiritShotChance() { return _spiritShotChance; } public int getMinSkillChance() { return _minSkillChance; } public int getMaxSkillChance() { return _maxSkillChance; } public int getPrimarySkillId() { return _primarySkillId; } public int getShortRangeSkillId() { return _shortRangeSkillId; } public int getShortRangeSkillChance() { return _shortRangeSkillChance; } public int getLongRangeSkillId() { return _longRangeSkillId; } public int getLongRangeSkillChance() { return _longRangeSkillChance; } @Override public Map<Integer, Skill> getSkills() { return _skills; } public void setSkills(Map<Integer, Skill> skills) { _skills = skills != null ? Collections.unmodifiableMap(skills) : Collections.<Integer, Skill> emptyMap(); } public List<Skill> getAISkills(AISkillScope aiSkillScope) { final List<Skill> aiSkills = _aiSkillLists.get(aiSkillScope); return aiSkills != null ? aiSkills : Collections.<Skill> emptyList(); } public void setAISkillLists(Map<AISkillScope, List<Skill>> aiSkillLists) { _aiSkillLists = aiSkillLists != null ? Collections.unmodifiableMap(aiSkillLists) : Collections.<AISkillScope, List<Skill>> emptyMap(); } public Set<Integer> getClans() { return _clans; } /** * @param clans A sorted array of clan ids */ public void setClans(Set<Integer> clans) { _clans = clans != null ? Collections.unmodifiableSet(clans) : null; } /** * @param clanName clan name to check if it belongs to this NPC template clans. * @param clanNames clan names to check if they belong to this NPC template clans. * @return {@code true} if at least one of the clan names belong to this NPC template clans, {@code false} otherwise. */ public boolean isClan(String clanName, String... clanNames) { // Using local variable for the sake of reloading since it can be turned to null. final Set<Integer> clans = _clans; if (clans == null) { return false; } int clanId = NpcData.getInstance().getClanId("ALL"); if (clans.contains(clanId)) { return true; } clanId = NpcData.getInstance().getClanId(clanName); if (clans.contains(clanId)) { return true; } for (String name : clanNames) { clanId = NpcData.getInstance().getClanId(name); if (clans.contains(clanId)) { return true; } } return false; } /** * @param clans A set of clan names to check if they belong to this NPC template clans. * @return {@code true} if at least one of the clan names belong to this NPC template clans, {@code false} otherwise. */ public boolean isClan(Set<Integer> clans) { // Using local variable for the sake of reloading since it can be turned to null. final Set<Integer> clanSet = _clans; if ((clanSet == null) || (clans == null)) { return false; } int clanId = NpcData.getInstance().getClanId("ALL"); if (clanSet.contains(clanId)) { return true; } for (Integer id : clans) { if (clanSet.contains(id)) { return true; } } return false; } public Set<Integer> getIgnoreClanNpcIds() { return _ignoreClanNpcIds; } /** * @param ignoreClanNpcIds the ignore clan npc ids */ public void setIgnoreClanNpcIds(Set<Integer> ignoreClanNpcIds) { _ignoreClanNpcIds = ignoreClanNpcIds != null ? Collections.unmodifiableSet(ignoreClanNpcIds) : null; } public Map<DropListScope, List<IDropItem>> getDropLists() { return _dropLists; } public void setDropLists(Map<DropListScope, List<IDropItem>> dropLists) { _dropLists = dropLists != null ? Collections.unmodifiableMap(dropLists) : null; } public List<IDropItem> getDropList(DropListScope dropListScope) { Map<DropListScope, List<IDropItem>> dropLists = _dropLists; return dropLists != null ? dropLists.get(dropListScope) : null; } public Collection<ItemHolder> calculateDrops(DropListScope dropListScope, L2Character victim, L2Character killer) { List<IDropItem> dropList = getDropList(dropListScope); if (dropList == null) { return null; } Collection<ItemHolder> calculatedDrops = null; for (IDropItem dropItem : dropList) { final Collection<ItemHolder> drops = dropItem.calculateDrops(victim, killer); if ((drops == null) || drops.isEmpty()) { continue; } if (calculatedDrops == null) { calculatedDrops = new LinkedList<>(); } calculatedDrops.addAll(drops); } return calculatedDrops; } public double getCollisionRadiusGrown() { return _collisionRadiusGrown; } public double getCollisionHeightGrown() { return _collisionHeightGrown; } public static boolean isAssignableTo(Class<?> sub, Class<?> clazz) { // If clazz represents an interface if (clazz.isInterface()) { // check if obj implements the clazz interface Class<?>[] interfaces = sub.getInterfaces(); for (Class<?> interface1 : interfaces) { if (clazz.getName().equals(interface1.getName())) { return true; } } } else { do { if (sub.getName().equals(clazz.getName())) { return true; } sub = sub.getSuperclass(); } while (sub != null); } return false; } /** * Checks if obj can be assigned to the Class represented by clazz.<br> * This is true if, and only if, obj is the same class represented by clazz, or a subclass of it or obj implements the interface represented by clazz. * @param obj * @param clazz * @return {@code true} if the object can be assigned to the class, {@code false} otherwise */ public static boolean isAssignableTo(Object obj, Class<?> clazz) { return L2NpcTemplate.isAssignableTo(obj.getClass(), clazz); } public boolean canTeach(ClassId classId) { // If the player is on a third class, fetch the class teacher // information for its parent class. if (classId.level() == 3) { return _teachInfo.contains(classId.getParent()); } return _teachInfo.contains(classId); } public List<ClassId> getTeachInfo() { return _teachInfo; } public void addTeachInfo(List<ClassId> teachInfo) { _teachInfo.addAll(teachInfo); } }