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 lineage2.gameserver.model; import gnu.trove.list.array.TIntArrayList; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.set.hash.TIntHashSet; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import lineage2.gameserver.skills.EffectType; import lineage2.gameserver.skills.effects.EffectTemplate; import lineage2.gameserver.skills.skillclasses.Transformation; import lineage2.gameserver.stats.Stats; import lineage2.gameserver.stats.funcs.FuncTemplate; import org.apache.commons.lang3.ArrayUtils; /** * @author Mobius * @version $Revision: 1.0 $ */ public class EffectList { /** * Field NONE_SLOT_TYPE. (value is -1) */ public static final int NONE_SLOT_TYPE = -1; /** * Field BUFF_SLOT_TYPE. (value is 0) */ public static final int BUFF_SLOT_TYPE = 0; /** * Field MUSIC_SLOT_TYPE. (value is 1) */ public static final int MUSIC_SLOT_TYPE = 1; /** * Field TRIGGER_SLOT_TYPE. (value is 2) */ public static final int TRIGGER_SLOT_TYPE = 2; /** * Field DEBUFF_SLOT_TYPE. (value is 3) */ public static final int DEBUFF_SLOT_TYPE = 3; /** * Field DEBUFF_LIMIT. (value is 8) */ public static final int DEBUFF_LIMIT = 8; /** * Field MUSIC_LIMIT. (value is 12) */ public static final int MUSIC_LIMIT = 12; /** * Field TRIGGER_LIMIT. (value is 12) */ public static final int TRIGGER_LIMIT = 12; /** * Field _actor. */ private final Creature _actor; /** * Field _effects. */ private List<Effect> _effects; /** * Field lock. */ private final Lock lock = new ReentrantLock(); /** * Constructor for EffectList. * @param owner Creature */ public EffectList(Creature owner) { _actor = owner; } /** * Method getEffectsCountForSkill. * @param skill_id int * @return int */ public int getEffectsCountForSkill(int skill_id) { if (isEmpty()) { return 0; } int count = 0; for (Effect e : _effects) { if (e.getSkill().getId() == skill_id) { count++; } } return count; } /** * Method getEffectByType. * @param et EffectType * @return Effect */ public Effect getEffectByType(EffectType et) { if (isEmpty()) { return null; } for (Effect e : _effects) { if (e.getEffectType() == et) { return e; } } return null; } /** * Method getEffectsBySkill. * @param skill Skill * @return List<Effect> */ public List<Effect> getEffectsBySkill(Skill skill) { if (skill == null) { return null; } return getEffectsBySkillId(skill.getId()); } /** * Method getEffectsBySkillId. * @param skillId int * @return List<Effect> */ public List<Effect> getEffectsBySkillId(int skillId) { if (isEmpty()) { return null; } List<Effect> list = new ArrayList<>(2); for (Effect e : _effects) { if (e.getSkill().getId() == skillId) { list.add(e); } } return list.isEmpty() ? null : list; } /** * Method getEffectByIndexAndType. * @param skillId int * @param type EffectType * @return Effect */ public Effect getEffectByIndexAndType(int skillId, EffectType type) { if (isEmpty()) { return null; } for (Effect e : _effects) { if ((e.getSkill().getId() == skillId) && (e.getEffectType() == type)) { return e; } } return null; } /** * Method getEffectByStackType. * @param type String * @return Effect */ public Effect getEffectByStackType(String type) { if (isEmpty()) { return null; } for (Effect e : _effects) { if (e.getStackType().contains(type)) { return e; } } return null; } /** * Method containEffectFromSkills. * @param skillIds int[] * @return boolean */ public boolean containEffectFromSkills(int[] skillIds) { if (isEmpty()) { return false; } int skillId; for (Effect e : _effects) { skillId = e.getSkill().getId(); if (ArrayUtils.contains(skillIds, skillId)) { return true; } } return false; } /** * Method containEffectFromSkill. * @param skillId integer * @param removeEffects boolean * @return boolean */ public boolean containEffectFromSkillId(int skillId, boolean removeEffects) { boolean contain = false; if (isEmpty()) { return contain; } for (Effect e : _effects) { if (skillId == e.getSkill().getId()) { contain = true; e.exit(); } } return contain; } /** * Method getAllEffects. * @return List<Effect> */ public List<Effect> getAllEffects() { if (isEmpty()) { return Collections.emptyList(); } return new ArrayList<>(_effects); } /** * Method isEmpty. * @return boolean */ public boolean isEmpty() { return (_effects == null) || _effects.isEmpty(); } /** * Method getAllFirstEffects. * @return Effect[] */ public Effect[] getAllFirstEffects() { if (isEmpty()) { return Effect.EMPTY_L2EFFECT_ARRAY; } TIntObjectHashMap<Effect> map = new TIntObjectHashMap<>(); for (Effect e : _effects) { map.put(e.getSkill().getId(), e); } return map.values(new Effect[map.size()]); } /** * Method checkSlotLimit. * @param newEffect Effect */ private void checkSlotLimit(Effect newEffect) { if (_effects == null) { return; } int slotType = getSlotType(newEffect); if (slotType == NONE_SLOT_TYPE) { return; } int size = 0; TIntArrayList skillIds = new TIntArrayList(); for (Effect e : _effects) { if (e.isInUse()) { if (e.getSkill().equals(newEffect.getSkill())) { return; } if (!skillIds.contains(e.getSkill().getId())) { int subType = getSlotType(e); if (subType == slotType) { size++; skillIds.add(e.getSkill().getId()); } } } } int limit = 0; switch (slotType) { case BUFF_SLOT_TYPE: limit = _actor.getBuffLimit(); break; case MUSIC_SLOT_TYPE: limit = MUSIC_LIMIT; break; case DEBUFF_SLOT_TYPE: limit = DEBUFF_LIMIT; break; case TRIGGER_SLOT_TYPE: limit = TRIGGER_LIMIT; break; } if (size < limit) { return; } int skillId = 0; for (Effect e : _effects) { if (e.isInUse()) { if (getSlotType(e) == slotType) { skillId = e.getSkill().getId(); break; } } } if (skillId != 0) { stopEffect(skillId); } } /** * Method getSlotType. * @param e Effect * @return int */ public static int getSlotType(Effect e) { if (e.getSkill().isPassive() || e.getSkill().isToggle() || (e.getSkill() instanceof Transformation) || e.getStackType().contains(EffectTemplate.HP_RECOVER_CAST) || (e.getEffectType() == EffectType.Cubic)) { return NONE_SLOT_TYPE; } else if (e.getSkill().isOffensive()) { return DEBUFF_SLOT_TYPE; } else if (e.getSkill().isMusic()) { return MUSIC_SLOT_TYPE; } else if (e.getSkill().isTrigger()) { return TRIGGER_SLOT_TYPE; } else { return BUFF_SLOT_TYPE; } } /** * Method checkStackType. * @param ef1 EffectTemplate * @param ef2 EffectTemplate * @return boolean */ public static boolean checkStackType(EffectTemplate ef1, EffectTemplate ef2) { if (!ef1._stackTypes.contains(EffectTemplate.NO_STACK)) { for (String arg : ef2._stackTypes) { if (ef1._stackTypes.contains(arg)) { return true; } } } return false; } /** * Method addEffect. * @param effect Effect */ public void addEffect(Effect effect) { double hp = _actor.getCurrentHp(); double mp = _actor.getCurrentMp(); double cp = _actor.getCurrentCp(); boolean add = false; lock.lock(); try { if (_effects == null) { _effects = new CopyOnWriteArrayList<>(); } if (effect.getStackType().contains(EffectTemplate.NO_STACK)) { for (Effect e : _effects) { if (!e.isInUse()) { continue; } if (e.getStackType().contains(EffectTemplate.NO_STACK) && (e.getSkill().getId() == effect.getSkill().getId()) && (e.getEffectType() == effect.getEffectType())) { if (effect.getTimeLeft() > e.getTimeLeft()) { e.exit(); } else { return; } } } } else { for (Effect e : _effects) { if (!e.isInUse()) { continue; } if (!checkStackType(e.getTemplate(), effect.getTemplate())) { continue; } if ((e.getSkill().getId() == effect.getSkill().getId()) && (e.getEffectType() != effect.getEffectType())) { break; } if (e.getStackOrder() == -1) { return; } if (!e.maybeScheduleNext(effect)) { return; } } } checkSlotLimit(effect); add = _effects.add(effect); if (add) { effect.setInUse(true); } } finally { lock.unlock(); } if (!add) { return; } effect.start(); for (FuncTemplate ft : effect.getTemplate().getAttachedFuncs()) { if (ft._stat == Stats.MAX_HP) { _actor.setCurrentHp(hp, false); } else if (ft._stat == Stats.MAX_MP) { _actor.setCurrentMp(mp); } else if (ft._stat == Stats.MAX_CP) { _actor.setCurrentCp(cp); } } _actor.updateStats(); _actor.updateEffectIcons(); } /** * Method removeEffect. * @param effect Effect */ public void removeEffect(Effect effect) { if (effect == null) { return; } boolean remove = false; lock.lock(); try { if (_effects == null) { return; } if (!((remove = _effects.remove(effect)))) { return; } } finally { lock.unlock(); } if (!remove) { return; } _actor.updateStats(); _actor.updateEffectIcons(); } /** * Method removeEffect. * @param skillId int */ public void removeEffect(int skillId) { if (isEmpty()) { return; } for (Effect e : _effects) { if (e.getSkill().getId() == skillId) { boolean remove = false; lock.lock(); try { if (_effects == null) { return; } if (!((remove = _effects.remove(e)))) { return; } } finally { lock.unlock(); } if (!remove) { return; } _actor.updateStats(); _actor.updateEffectIcons(); } } } /** * Method stopAllEffects. */ public void stopAllEffects() { if (isEmpty()) { return; } lock.lock(); try { for (Effect e : _effects) { e.exit(); } } finally { lock.unlock(); } _actor.updateStats(); _actor.updateEffectIcons(); } /** * Method stopEffect. * @param skillId int */ public void stopEffect(int skillId) { if (isEmpty()) { return; } for (Effect e : _effects) { if (e.getSkill().getId() == skillId) { e.exit(); } } } /** * Method stopEffect. * @param skill Skill */ public void stopEffect(Skill skill) { if (skill != null) { stopEffect(skill.getId()); } } /** * Method stopEffectByDisplayId. * @param skillId int */ public void stopEffectByDisplayId(int skillId) { if (isEmpty()) { return; } for (Effect e : _effects) { if (e.getSkill().getDisplayId() == skillId) { e.exit(); } } } /** * Method stopEffects. * @param type EffectType */ public void stopEffects(EffectType type) { if (isEmpty()) { return; } for (Effect e : _effects) { if (e.getEffectType() == type) { e.exit(); } } } /** * Method stopAllSkillEffects. * @param type EffectType */ public void stopAllSkillEffects(EffectType type) { if (isEmpty()) { return; } TIntHashSet skillIds = new TIntHashSet(); for (Effect e : _effects) { if (e.getEffectType() == type) { skillIds.add(e.getSkill().getId()); } } for (int skillId : skillIds.toArray()) { stopEffect(skillId); } } }