staige2973 0 Опубликовано 23 мая, 2017 (изменено) При баффе, эффекты накладываются рандомно, а не по порядку. Еще при удалении эффектов по одному, они перемещаются. Пример: бафф акумен стоял в самом начале, я удалю любой другой бафф, а акумен переместится в конец. Как сделать, что бы баффы не перемещались? package l2p.gameserver.model; import java.util.concurrent.Future;import java.util.concurrent.atomic.AtomicInteger;import l2p.commons.threading.RunnableImpl;import l2p.gameserver.Config;import l2p.gameserver.listener.actor.OnAttackListener;import l2p.gameserver.listener.actor.OnMagicUseListener;import l2p.gameserver.masteriopack.bbsbuffer.BBSBuffer;import l2p.gameserver.masteriopack.bbsbuffer.BBSBufferConfig;import l2p.gameserver.serverpackets.AbnormalStatusUpdate;import l2p.gameserver.serverpackets.ExOlympiadSpelledInfo;import l2p.gameserver.serverpackets.PartySpelled;import l2p.gameserver.serverpackets.ShortBuffStatusUpdate;import l2p.gameserver.serverpackets.SystemMessage;import l2p.gameserver.serverpackets.components.SystemMsg;import l2p.gameserver.skills.AbnormalEffect;import l2p.gameserver.skills.EffectType;import l2p.gameserver.skills.effects.EffectTemplate;import l2p.gameserver.stats.Env;import l2p.gameserver.stats.funcs.Func;import l2p.gameserver.stats.funcs.FuncOwner;import l2p.gameserver.tables.SkillTable;import l2p.gameserver.taskmanager.EffectTaskManager;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public abstract class Effect extends RunnableImpl implements Comparable, FuncOwner {private static final Logger _log = LoggerFactory.getLogger(Effect.class);public final static Effect[] EMPTY_L2EFFECT_ARRAY = new Effect[0];// Состояние, при котором работает задача запланированного эффектаpublic static int SUSPENDED = -1;public static int STARTING = 0;public static int STARTED = 1;public static int ACTING = 2;public static int FINISHING = 3;public static int FINISHED = 4;/*** Накладывающий эффект*/protected final Creature _effector;/*** Тот, на кого накладывают эффект*/protected final Creature _effected;protected final Skill _skill;protected final int _displayId;protected final int _displayLevel;// the value of an updateprivate final double _value;// the current stateprivate final AtomicInteger _state;// counterprivate int _count;// period, millisecondsprivate long _period;private long _startTimeMillis;private long _duration;private boolean _inUse = false;private Effect _next = null;private boolean _active = false;protected final EffectTemplate _template;private Future_effectTask;protected Effect(Env env, EffectTemplate template) {_skill = env.skill;_effector = env.character;_effected = env.target;_template = template;_value = template._value;_count = template.getCount();_period = template.getPeriod();_duration = _period * _count;_displayId = template._displayId != 0 ? template._displayId : _skill.getDisplayId();_displayLevel = template._displayLevel != 0 ? template._displayLevel : _skill.getDisplayLevel();_state = new AtomicInteger(STARTING);}public long getPeriod() {return _period;}public void setPeriod(long time) {_period = time;_duration = _period * _count;}public int getCount() {return _count;}public void setCount(int count) {_count = count;_duration = _period * _count;}public boolean isOneTime() {return _period == 0;}/*** Возвращает время старта эффекта, если время не установлено, возвращается* текущее*/public long getStartTime() {if (_startTimeMillis == 0L) {return System.currentTimeMillis();}return _startTimeMillis;}/*** Возвращает общее время действия эффекта в миллисекундах.*/public long getTime() {return System.currentTimeMillis() - getStartTime();}/*** Возвращает длительность эффекта в миллисекундах.*/public long getDuration() {return _duration;}/*** Возвращает оставшееся время в секундах.*/public int getTimeLeft() {return (int) ((getDuration() - getTime()) / 1000L);}/*** Возвращает true, если осталось время для действия эффекта*/public boolean isTimeLeft() {return getDuration() - getTime() > 0L;}public boolean isInUse() {return _inUse;}public void setInUse(boolean inUse) {_inUse = inUse;}public boolean isActive() {return _active;}/*** Для неактивных эфектов не вызывается onActionTime.*/public void setActive(boolean set) {_active = set;}public EffectTemplate getTemplate() {return _template;}public String getStackType() {return getTemplate()._stackType;}public String getStackType2() {return getTemplate()._stackType2;}public boolean checkStackType(String param) {return getStackType().equalsIgnoreCase(param) || getStackType2().equalsIgnoreCase(param);}public boolean checkStackType(Effect param) {return checkStackType(param.getStackType()) || checkStackType(param.getStackType2());}public int getStackOrder() {return getTemplate()._stackOrder;}public Skill getSkill() {return _skill;}public Creature getEffector() {return _effector;}public Creature getEffected() {return _effected;}public double calc() {return _value;}public boolean isEnded() {return isFinished() || isFinishing();}public boolean isFinishing() {return getState() == FINISHING;}public boolean isFinished() {return getState() == FINISHED;}private int getState() {return _state.get();}private boolean setState(int oldState, int newState) {return _state.compareAndSet(oldState, newState);}private ActionDispelListener _listener;private class ActionDispelListener implements OnAttackListener, OnMagicUseListener {@@overridepublic void onMagicUse(Creature actor, Skill skill, Creature target, boolean alt) {exit();}@@overridepublic void onAttack(Creature actor, Creature target) {exit();}}public boolean checkCondition() {return true;}/*** Notify started*/protected void onStart() {getEffected().addStatFuncs(getStatFuncs());getEffected().addTriggers(getTemplate());if (getTemplate()._abnormalEffect != AbnormalEffect.NULL) {getEffected().startAbnormalEffect(getTemplate()._abnormalEffect);} else if (getEffectType().getAbnormal() != null) {getEffected().startAbnormalEffect(getEffectType().getAbnormal());}if (getTemplate()._abnormalEffect2 != AbnormalEffect.NULL) {getEffected().startAbnormalEffect(getTemplate()._abnormalEffect2);}if (getTemplate()._abnormalEffect3 != AbnormalEffect.NULL) {getEffected().startAbnormalEffect(getTemplate()._abnormalEffect3);}if (_template._cancelOnAction) {getEffected().addListener(_listener = new ActionDispelListener());}if (getEffected().isPlayer() && !getSkill().canUseTeleport()) {getEffected().getPlayer().getPlayerAccess().UseTeleport = false;}}/*** Return true for continuation of this effect*/protected abstract boolean onActionTime();/*** Cancel the effect in the the abnormal effect map of the effected* L2Character.**/protected void onExit() {getEffected().removeStatsOwner(this);getEffected().removeTriggers(getTemplate());if (getTemplate()._abnormalEffect != AbnormalEffect.NULL) {getEffected().stopAbnormalEffect(getTemplate()._abnormalEffect);} else if (getEffectType().getAbnormal() != null) {getEffected().stopAbnormalEffect(getEffectType().getAbnormal());}if (getTemplate()._abnormalEffect2 != AbnormalEffect.NULL) {getEffected().stopAbnormalEffect(getTemplate()._abnormalEffect2);}if (getTemplate()._abnormalEffect3 != AbnormalEffect.NULL) {getEffected().stopAbnormalEffect(getTemplate()._abnormalEffect3);}if (_template._cancelOnAction) {getEffected().removeListener(_listener);}if (getEffected().isPlayer() && getStackType().equals(EffectTemplate.HP_RECOVER_CAST)) {getEffected().sendPacket(new ShortBuffStatusUpdate());}if (getEffected().isPlayer() && !getSkill().canUseTeleport()&& !getEffected().getPlayer().getPlayerAccess().UseTeleport) {getEffected().getPlayer().getPlayerAccess().UseTeleport = true;}// BBS Buffer by Masterioif (BBSBufferConfig.AUTOREBUFF_ENABLED) {if (getEffected() instanceof Player) {BBSBuffer BB = ((Player) getEffected())._bbsbuffer;if (!BB.isRebuffPlayerTaskExecute() && BB.getRebuffPlayerSchemeId() > 0&& BB.isSkillInSchemeExists(getSkill().getId(), true)) {BB.startRebuffPlayerTaskSchedule();}} else if (getEffected() instanceof Summon) {BBSBuffer BB = getEffected().getPlayer()._bbsbuffer;if (!BB.isRebuffSummonTaskExecute() && BB.getRebuffSummonSchemeId() > 0&& BB.isSkillInSchemeExists(getSkill().getId(), false)) {BB.startRebuffSummonTaskSchedule();}}}}private void stopEffectTask() {if (_effectTask != null) {_effectTask.cancel(false);}}private void startEffectTask() {if (_effectTask == null) {_startTimeMillis = System.currentTimeMillis();_effectTask = EffectTaskManager.getInstance().scheduleAtFixedRate(this, _period, _period);}}/*** Добавляет эффект в список эффектов, в случае успешности вызывается метод* start*/public final void schedule() {Creature effected = getEffected();if (effected == null) {return;}if (!checkCondition()) {return;}getEffected().getEffectList().addEffect(this);}/*** Переводит эффект в "фоновый" режим, эффект может быть запущен методом* schedule*/private void suspend() {// Эффект создан, запускаем задачу в фонеif (setState(STARTING, SUSPENDED)) {startEffectTask();} else if (setState(STARTED, SUSPENDED) || setState(ACTING, SUSPENDED)) {synchronized (this) {if (isInUse()) {setInUse(false);setActive(false);onExit();}}getEffected().getEffectList().removeEffect(this);}}/*** Запускает задачу эффекта, в случае если эффект успешно добавлен в список*/public final void start() {if (setState(STARTING, STARTED)) {synchronized (this) {if (isInUse()) {setActive(true);onStart();startEffectTask();}}}run();}@@overridepublic final void runImpl() throws Exception {if (setState(STARTED, ACTING)) {// Отображать сообщение только для первого эффекта скиллаif (!getSkill().isHideStartMessage()&& getEffected().getEffectList().getEffectsCountForSkill(getSkill().getId()) == 1) {getEffected().sendPacket(new SystemMessage(SystemMsg.S1_EFFECT_CAN_BE_FELT).addSkillName(_displayId, _displayLevel));}return;}if (getState() == SUSPENDED) {if (isTimeLeft()) {_count--;if (isTimeLeft()) {return;}}exit();return;}if (getState() == ACTING) {if (isTimeLeft()) {_count--;if ((!isActive() || onActionTime()) && isTimeLeft()) {return;}}}if (setState(ACTING, FINISHING)) {setInUse(false);}if (setState(FINISHING, FINISHED)) {synchronized (this) {setActive(false);stopEffectTask();onExit();}// Добавляем следующий запланированный эффектEffect next = getNext();if (next != null) {if (next.setState(SUSPENDED, STARTING)) {next.schedule();}}if (getSkill().getDelayedEffect() > 0) {Skill delayErrects = SkillTable.getInstance().getInfo(getSkill().getDelayedEffect(),getSkill().getDelayedEffectLvl());if (delayErrects != null) {delayErrects.getEffects(_effector, _effected, false, false);}}boolean msg = !isHidden() && getEffected().getEffectList().getEffectsCountForSkill(getSkill().getId()) == 1;getEffected().getEffectList().removeEffect(this);// Отображать сообщение только для последнего оставшегося эффекта// скиллаif (msg) {getEffected().sendPacket(new SystemMessage(SystemMsg.S1_HAS_WORN_OFF).addSkillName(_displayId, _displayLevel));}}}/*** Завершает эффект и все связанные, удаляет эффект из списка эффектов*/public final void exit() {Effect next = getNext();if (next != null) {next.exit();}removeNext();// Эффект запланирован на запуск, удаляемif (setState(STARTING, FINISHED)) {getEffected().getEffectList().removeEffect(this);} // Эффект работает в "фоне", останавливаем задачу в планировщикеelse if (setState(SUSPENDED, FINISHED)) {stopEffectTask();} else if (setState(STARTED, FINISHED) || setState(ACTING, FINISHED)) {synchronized (this) {if (isInUse()) {setInUse(false);setActive(false);stopEffectTask();onExit();}}getEffected().getEffectList().removeEffect(this);}}/*** Поставить в очередь эффект** @param e* * @return true, если эффект поставлен в очередь*/private boolean scheduleNext(Effect e) {if (e == null || e.isEnded()) {return false;}Effect next = getNext();if (next != null && !next.maybeScheduleNext(e)) {return false;}_next = e;return true;}public Effect getNext() {return _next;}private void removeNext() {_next = null;}/*** @return false - игнорировать новый эффект, true - использовать новый* эффект*/public boolean maybeScheduleNext(Effect newEffect) {if (newEffect.getStackOrder() < getStackOrder()) // новый эффект слабее{if (newEffect.getTimeLeft() > getTimeLeft()) // новый эффект длинее{newEffect.suspend();scheduleNext(newEffect); // пробуем пристроить новый эффект в// очередь}return false; // более слабый эффект всегда игнорируется, даже если// не попал в очередь} else // если старый не дольше, то просто остановить егоif (newEffect.getTimeLeft() >= getTimeLeft()) {// наследуем зашедуленый старому, если есть смыслif (getNext() != null && getNext().getTimeLeft() > newEffect.getTimeLeft()) {newEffect.scheduleNext(getNext());// отсоединяем зашедуленные от текущегоremoveNext();}exit();} else // если новый короче то зашедулить старый{suspend();newEffect.scheduleNext(this);}return true;}public Func[] getStatFuncs() {return getTemplate().getStatFuncs(this);}public void addIcon(AbnormalStatusUpdate mi) {if (!isActive() || isHidden()) {return;}int duration = _skill.isToggle() ? AbnormalStatusUpdate.INFINITIVE_EFFECT : getTimeLeft();mi.addEffect(_displayId, _displayLevel, duration);}public void addPartySpelledIcon(PartySpelled ps) {if (!isActive() || isHidden()) {return;}int duration = _skill.isToggle() ? AbnormalStatusUpdate.INFINITIVE_EFFECT : getTimeLeft();ps.addPartySpelledEffect(_displayId, _displayLevel, duration);}public void addOlympiadSpelledIcon(Player player, ExOlympiadSpelledInfo os) {if (!isActive() || isHidden()) {return;}int duration = _skill.isToggle() ? AbnormalStatusUpdate.INFINITIVE_EFFECT : getTimeLeft();os.addSpellRecivedPlayer(player);os.addEffect(_displayId, _displayLevel, duration);}protected int getLevel() {return _skill.getLevel();}public EffectType getEffectType() {return getTemplate()._effectType;}public boolean isHidden() {return _displayId < 0;}@@overridepublic int compareTo(Effect obj) {if (obj.equals(this)) {return 0;}return 1;}public boolean isSaveable() {return _template.isSaveable(getSkill().isSaveable()) && getTimeLeft() >= Config.ALT_SAVE_EFFECTS_REMAINING_TIME;}public int getDisplayId() {return _displayId;}public int getDisplayLevel() {return _displayLevel;}public boolean isCancelable() {return _template.isCancelable(getSkill().isCancelable());}@@overridepublic String toString() {return "Skill: " + _skill + ", state: " + getState() + ", inUse: " + _inUse + ", active : " + _active;}@@overridepublic boolean isFuncEnabled() {return isInUse();}@@overridepublic boolean overrideLimits() {return false;}public boolean isOffensive() {return _template.isOffensive(getSkill().isOffensive());}} package l2p.gameserver.model;import gnu.trove.list.array.TIntArrayList;import gnu.trove.map.hash.TIntObjectHashMap;import gnu.trove.set.hash.TIntHashSet;import l2p.gameserver.skills.EffectType;import l2p.gameserver.skills.effects.EffectTemplate;import l2p.gameserver.skills.skillclasses.Transformation;import l2p.gameserver.stats.Stats;import l2p.gameserver.stats.funcs.FuncTemplate;import org.apache.commons.lang3.ArrayUtils;import l2p.gameserver.Config;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;public class EffectList {public static final int NONE_SLOT_TYPE = -1;public static final int BUFF_SLOT_TYPE = 0;public static final int MUSIC_SLOT_TYPE = 1;public static final int TRIGGER_SLOT_TYPE = 2;public static final int DEBUFF_SLOT_TYPE = 3;private Creature _actor;private List _effects;private Lock lock = new ReentrantLock();public EffectList(Creature owner) {_actor = owner;}/*** Возвращает число эффектов соответствующее данному скиллу*/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;}public Effect getEffectByType(EffectType et) {if (isEmpty()) {return null;}for (Effect e : _effects) {if (e.getEffectType() == et) {return e;}}return null;}public List getEffectsBySkill(Skill skill) {if (skill == null) {return null;}return getEffectsBySkillId(skill.getId());}public List getEffectsBySkillId(int skillId) {if (isEmpty()) {return null;}List list = new ArrayList(2);for (Effect e : _effects) {if (e.getSkill().getId() == skillId) {list.add(e);}}return list.isEmpty() ? null : list;}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;}public Effect getEffectByStackType(String type) {if (isEmpty()) {return null;}for (Effect e : _effects) {if (e.getStackType().equalsIgnoreCase(type)) {return e;}}return null;}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;}public List getAllEffects() {if (isEmpty()) {return Collections.emptyList();}return new ArrayList(_effects);}public boolean isEmpty() {return _effects == null || _effects.isEmpty();}/*** Возвращает первые эффекты для всех скиллов. Нужно для отображения не* более чем 1 иконки для каждого скилла.*/public Effect[] getAllFirstEffects() {if (isEmpty()) {return Effect.EMPTY_L2EFFECT_ARRAY;}TIntObjectHashMap map = new TIntObjectHashMap();for (Effect e : _effects) {map.put(e.getSkill().getId(), e);}return map.values(new Effect[map.size()]);}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 = Config.ALT_MUSIC_LIMIT;break;case DEBUFF_SLOT_TYPE:limit = Config.ALT_DEBUFF_LIMIT;break;case TRIGGER_SLOT_TYPE:limit = Config.ALT_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);}}public static int getSlotType(Effect e) {if (e.getSkill().isPassive() || e.getSkill().isToggle() || e.getSkill() instanceof Transformation|| e.getStackType().equals(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;}}public static boolean checkStackType(EffectTemplate ef1, EffectTemplate ef2) {if (!ef1._stackType.equals(EffectTemplate.NO_STACK) && ef1._stackType.equalsIgnoreCase(ef2._stackType)) {return true;}if (!ef1._stackType.equals(EffectTemplate.NO_STACK) && ef1._stackType.equalsIgnoreCase(ef2._stackType2)) {return true;}if (!ef1._stackType2.equals(EffectTemplate.NO_STACK) && ef1._stackType2.equalsIgnoreCase(ef2._stackType)) {return true;}if (!ef1._stackType2.equals(EffectTemplate.NO_STACK) && ef1._stackType2.equalsIgnoreCase(ef2._stackType2)) {return true;}return false;}public void addEffect(Effect effect) {// TODO [G1ta0] затычка на статы повышающие HP/MP/CPdouble hp = _actor.getCurrentHp();double mp = _actor.getCurrentMp();double cp = _actor.getCurrentCp();String stackType = effect.getStackType();boolean add = false;lock.lock();try {if (_effects == null) {_effects = new CopyOnWriteArrayList();}if (stackType.equals(EffectTemplate.NO_STACK)) // Удаляем такие же// эффекты{for (Effect e : _effects) {if (!e.isInUse()) {continue;}if (e.getStackType().equals(EffectTemplate.NO_STACK)&& e.getSkill().getId() == effect.getSkill().getId()&& e.getEffectType() == effect.getEffectType()) // Если// оставшаяся// длительность// старого// эффекта// больше// чем// длительность// нового,// то// оставляем// старый.{if (effect.getTimeLeft() > e.getTimeLeft()) {e.exit();} else {return;}}}} else // Проверяем, нужно ли накладывать эффект, при совпадении// StackType.// Новый эффект накладывается только в том случае, если у него// больше StackOrder и больше длительность.// Если условия подходят - удаляем старый.{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;}// Эффекты со StackOrder == -1 заменить нельзя (например,// Root).if (e.getStackOrder() == -1) {return;}if (!e.maybeScheduleNext(effect)) {return;}}}// Проверяем на лимиты бафов/дебафовcheckSlotLimit(effect);// Добавляем новый эффектif (add = _effects.add(effect)) {effect.setInUse(true);}} finally {lock.unlock();}if (!add) {return;}// Запускаем эффектeffect.start();// TODO [G1ta0] затычка на статы повышающие HP/MP/CPfor (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();}/*** Удаление эффекта из списка** @param 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();}public void stopAllEffects() {if (isEmpty()) {return;}lock.lock();try {for (Effect e : _effects) {e.exit();}} finally {lock.unlock();}_actor.updateStats();_actor.updateEffectIcons();}public void stopEffect(int skillId) {if (isEmpty()) {return;}for (Effect e : _effects) {if (e.getSkill().getId() == skillId) {e.exit();}}}public void stopEffect(Skill skill) {if (skill != null) {stopEffect(skill.getId());}}public void stopEffectByDisplayId(int skillId) {if (isEmpty()) {return;}for (Effect e : _effects) {if (e.getSkill().getDisplayId() == skillId) {e.exit();}}}public void stopEffects(EffectType type) {if (isEmpty()) {return;}for (Effect e : _effects) {if (e.getEffectType() == type) {e.exit();}}}/*** Находит скиллы с указанным эффектом, и останавливает у этих скиллов все* эффекты (не только указанный).*/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);}}} Изменено 23 мая, 2017 пользователем staige2973 Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты