123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305 |
- /*
- * 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.l2jserver.gameserver.model;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.LinkedBlockingQueue;
- import java.util.concurrent.atomic.AtomicBoolean;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import javolution.util.FastList;
- import javolution.util.FastMap;
- import com.l2jserver.Config;
- import com.l2jserver.gameserver.model.actor.L2Character;
- import com.l2jserver.gameserver.model.actor.L2Playable;
- import com.l2jserver.gameserver.model.actor.L2Summon;
- import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
- import com.l2jserver.gameserver.model.olympiad.OlympiadGameManager;
- import com.l2jserver.gameserver.model.olympiad.OlympiadGameTask;
- import com.l2jserver.gameserver.network.SystemMessageId;
- import com.l2jserver.gameserver.network.serverpackets.AbnormalStatusUpdate;
- import com.l2jserver.gameserver.network.serverpackets.ExOlympiadSpelledInfo;
- import com.l2jserver.gameserver.network.serverpackets.PartySpelled;
- import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
- import com.l2jserver.gameserver.templates.skills.L2EffectType;
- import com.l2jserver.gameserver.templates.skills.L2SkillType;
- public class CharEffectList
- {
- protected static final Logger _log = Logger.getLogger(CharEffectList.class.getName());
- private static final L2Effect[] EMPTY_EFFECTS = new L2Effect[0];
-
- public static final int EFFECT_FLAG_CHARM_OF_COURAGE = 0x1;
- public static final int EFFECT_FLAG_CHARM_OF_LUCK = 0x2;
- public static final int EFFECT_FLAG_PHOENIX_BLESSING = 0x4;
- public static final int EFFECT_FLAG_NOBLESS_BLESSING = 0x8;
- public static final int EFFECT_FLAG_SILENT_MOVE = 0x10;
- public static final int EFFECT_FLAG_PROTECTION_BLESSING = 0x20;
- public static final int EFFECT_FLAG_RELAXING = 0x40;
- public static final int EFFECT_FLAG_FEAR = 0x80;
- public static final int EFFECT_FLAG_CONFUSED = 0x100;
- public static final int EFFECT_FLAG_MUTED = 0x200;
- public static final int EFFECT_FLAG_PSYCHICAL_MUTED = 0x400;
- //public static final int EFFECT_FLAG_PARALYZE = 2048; //too much abuse in code
- public static final int EFFECT_FLAG_PSYCHICAL_ATTACK_MUTED = 0x800;
- public static final int EFFECT_FLAG_DISARMED = 0x1000;
- public static final int EFFECT_FLAG_ROOTED = 0x2000;
- public static final int EFFECT_FLAG_SLEEP = 0x4000;
- public static final int EFFECT_FLAG_STUNNED = 0x8000;
- public static final int EFFECT_FLAG_BETRAYED = 0x10000;
- public static final int EFFECT_FLAG_INVUL = 0x40000;
- public static final int EFFECT_FLAG_PARALYZED = 0x80000;
- public static final int EFFECT_FLAG_BLOCK_RESURRECTION = 0x100000;
-
- private FastList<L2Effect> _buffs;
- private FastList<L2Effect> _debuffs;
-
- // The table containing the List of all stacked effect in progress for each Stack group Identifier
- private Map<String, List<L2Effect>> _stackedEffects;
-
- private volatile boolean _hasBuffsRemovedOnAnyAction = false;
- private volatile boolean _hasBuffsRemovedOnDamage = false;
- private volatile boolean _hasDebuffsRemovedOnDamage = false;
-
- private boolean _queuesInitialized = false;
- private LinkedBlockingQueue<L2Effect> _addQueue;
- private LinkedBlockingQueue<L2Effect> _removeQueue;
- private AtomicBoolean queueLock = new AtomicBoolean();
- private int _effectFlags;
-
- // only party icons need to be updated
- private boolean _partyOnly = false;
-
- // Owner of this list
- private L2Character _owner;
-
- public CharEffectList(L2Character owner)
- {
- _owner = owner;
- }
-
- /**
- * Returns all effects affecting stored in this CharEffectList
- * @return
- */
- public final L2Effect[] getAllEffects()
- {
- // If no effect is active, return EMPTY_EFFECTS
- if ( (_buffs == null || _buffs.isEmpty()) && (_debuffs == null || _debuffs.isEmpty()) )
- {
- return EMPTY_EFFECTS;
- }
-
- // Create a copy of the effects
- FastList<L2Effect> temp = FastList.newInstance();
-
- // Add all buffs and all debuffs
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- temp.addAll(_buffs);
- }
- }
- if (_debuffs != null)
- {
- //synchronized (_debuffs)
- {
- if (!_debuffs.isEmpty())
- temp.addAll(_debuffs);
- }
- }
-
- // Return all effects in an array
- L2Effect[] tempArray = new L2Effect[temp.size()];
- temp.toArray(tempArray);
- FastList.recycle(temp);
- return tempArray;
- }
-
- /**
- * Returns the first effect matching the given EffectType
- * @param tp
- * @return
- */
- public final L2Effect getFirstEffect(L2EffectType tp)
- {
- L2Effect effectNotInUse = null;
-
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e: _buffs)
- {
- if (e == null)
- continue;
- if (e.getEffectType() == tp)
- {
- if (e.getInUse())
- return e;
- else
- effectNotInUse = e;
- }
- }
- }
- }
- }
- if (effectNotInUse == null && _debuffs != null)
- {
- //synchronized (_debuffs)
- {
- if (!_debuffs.isEmpty())
- {
- for (L2Effect e: _debuffs)
- {
- if (e == null)
- continue;
- if (e.getEffectType() == tp)
- {
- if (e.getInUse())
- return e;
- else
- effectNotInUse = e;
- }
- }
- }
- }
- }
- return effectNotInUse;
- }
-
- /**
- * Returns the first effect matching the given L2Skill
- * @param skill
- * @return
- */
- public final L2Effect getFirstEffect(L2Skill skill)
- {
- L2Effect effectNotInUse = null;
-
- if (skill.isDebuff())
- {
- if (_debuffs == null)
- return null;
-
- //synchronized (_debuffs)
- {
- if (_debuffs.isEmpty())
- return null;
-
- for (L2Effect e: _debuffs)
- {
- if (e == null)
- continue;
- if (e.getSkill() == skill)
- {
- if (e.getInUse())
- return e;
- else
- effectNotInUse = e;
- }
- }
- }
- return effectNotInUse;
- }
- else
- {
- if (_buffs == null)
- return null;
-
- //synchronized (_buffs)
- {
- if (_buffs.isEmpty())
- return null;
-
- for (L2Effect e: _buffs)
- {
- if (e == null)
- continue;
- if (e.getSkill() == skill)
- {
- if (e.getInUse())
- return e;
- else
- effectNotInUse = e;
- }
- }
- }
- return effectNotInUse;
- }
- }
-
- /**
- * Returns the first effect matching the given skillId
- * @param index
- * @return
- */
- public final L2Effect getFirstEffect(int skillId)
- {
- L2Effect effectNotInUse = null;
-
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e: _buffs)
- {
- if (e == null)
- continue;
- if (e.getSkill().getId() == skillId)
- {
- if (e.getInUse())
- return e;
- else
- effectNotInUse = e;
- }
- }
- }
- }
- }
-
- if (effectNotInUse == null && _debuffs != null)
- {
- //synchronized (_debuffs)
- {
- if (!_debuffs.isEmpty())
- {
- for (L2Effect e: _debuffs)
- {
- if (e == null)
- continue;
- if (e.getSkill().getId() == skillId)
- {
- if (e.getInUse())
- return e;
- else
- effectNotInUse = e;
- }
- }
- }
- }
- }
-
- return effectNotInUse;
- }
-
- /**
- * Checks if the given skill stacks with an existing one.
- *
- * @param checkSkill the skill to be checked
- *
- * @return Returns whether or not this skill will stack
- */
- private boolean doesStack(L2Skill checkSkill)
- {
- if ( (_buffs == null || _buffs.isEmpty()) ||
- checkSkill._effectTemplates == null ||
- checkSkill._effectTemplates.length < 1 ||
- checkSkill._effectTemplates[0].abnormalType == null ||
- "none".equals(checkSkill._effectTemplates[0].abnormalType))
- {
- return false;
- }
-
- String stackType = checkSkill._effectTemplates[0].abnormalType;
-
- for (L2Effect e : _buffs)
- {
- if (e.getAbnormalType() != null && e.getAbnormalType().equals(stackType))
- {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Return the number of buffs in this CharEffectList not counting Songs/Dances
- * @return
- */
- public int getBuffCount()
- {
- if (_buffs == null) return 0;
- int buffCount=0;
-
- //synchronized(_buffs)
- {
- if (_buffs.isEmpty())
- return 0;
-
- for (L2Effect e : _buffs)
- {
- if (e != null && e.getShowIcon() && !e.getSkill().isDance() && !e.getSkill().is7Signs())
- {
- switch (e.getSkill().getSkillType())
- {
- case BUFF:
- case HEAL_PERCENT:
- case MANAHEAL_PERCENT:
- buffCount++;
- }
- }
- }
- }
- return buffCount;
- }
-
- /**
- * Return the number of Songs/Dances in this CharEffectList
- * @return
- */
- public int getDanceCount()
- {
- if (_buffs == null) return 0;
- int danceCount = 0;
-
- //synchronized(_buffs)
- {
- if (_buffs.isEmpty())
- return 0;
-
- for (L2Effect e : _buffs)
- {
- if (e != null && e.getSkill().isDance() && e.getInUse())
- danceCount++;
- }
- }
- return danceCount;
- }
-
- /**
- * Exits all effects in this CharEffectList
- */
- public final void stopAllEffects()
- {
- // Get all active skills effects from this list
- L2Effect[] effects = getAllEffects();
-
- // Exit them
- for (L2Effect e : effects)
- {
- if (e != null)
- e.exit(true);
- }
- }
-
- /**
- * Exits all effects in this CharEffectList
- */
- public final void stopAllEffectsExceptThoseThatLastThroughDeath()
- {
- // Get all active skills effects from this list
- L2Effect[] effects = getAllEffects();
-
- // Exit them
- for (L2Effect e : effects)
- {
- if (e != null && !e.getSkill().isStayAfterDeath())
- e.exit(true);
- }
- }
-
- /**
- * Exit all toggle-type effects
- */
- public void stopAllToggles()
- {
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e : _buffs)
- if (e != null && e.getSkill().isToggle())
- e.exit();
- }
- }
- }
- }
-
- /**
- * Exit all effects having a specified type
- * @param type
- */
- public final void stopEffects(L2EffectType type)
- {
- // Go through all active skills effects
- FastList<L2Effect> temp = FastList.newInstance();
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e : _buffs)
- // Get active skills effects of the selected type
- if (e != null && e.getEffectType() == type)
- temp.add(e);
- }
- }
- }
- if (_debuffs != null)
- {
- //synchronized (_debuffs)
- {
- if (!_debuffs.isEmpty())
- {
- for (L2Effect e : _debuffs)
- // Get active skills effects of the selected type
- if (e != null && e.getEffectType() == type)
- temp.add(e);
- }
- }
- }
- if (!temp.isEmpty())
- {
- for (L2Effect e : temp)
- if (e != null)
- e.exit();
- }
- FastList.recycle(temp);
- }
-
- /**
- * Exits all effects created by a specific skillId
- * @param skillId
- */
- public final void stopSkillEffects(int skillId)
- {
- // Go through all active skills effects
- FastList<L2Effect> temp = FastList.newInstance();
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e : _buffs)
- if (e != null && e.getSkill().getId() == skillId)
- temp.add(e);
- }
- }
- }
- if (_debuffs != null)
- {
- //synchronized (_debuffs)
- {
- if (!_debuffs.isEmpty())
- {
- for (L2Effect e : _debuffs)
- if (e != null && e.getSkill().getId() == skillId)
- temp.add(e);
- }
- }
- }
- if (!temp.isEmpty())
- {
- for (L2Effect e : temp)
- if (e != null)
- e.exit();
- }
- FastList.recycle(temp);
- }
-
- /**
- * Exits all effects created by a specific skill type
- * @param skillType skill type
- */
- public final void stopSkillEffects(L2SkillType skillType, int negateLvl)
- {
- // Go through all active skills effects
- FastList<L2Effect> temp = FastList.newInstance();
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e : _buffs)
- {
- if (e != null && (e.getSkill().getSkillType() == skillType || (e.getSkill().getEffectType() != null && e.getSkill().getEffectType() == skillType))
- && (negateLvl == -1 || (e.getSkill().getEffectType() != null && e.getSkill().getEffectAbnormalLvl() >= 0 && e.getSkill().getEffectAbnormalLvl() <= negateLvl) || (e.getSkill().getAbnormalLvl() >= 0 && e.getSkill().getAbnormalLvl() <= negateLvl)))
- temp.add(e);
- }
- }
- }
- }
- if (_debuffs != null)
- {
- //synchronized (_debuffs)
- {
- if (!_debuffs.isEmpty())
- {
- for (L2Effect e : _debuffs)
- {
- if (e != null && (e.getSkill().getSkillType() == skillType || (e.getSkill().getEffectType() != null && e.getSkill().getEffectType() == skillType))
- && (negateLvl == -1 || (e.getSkill().getEffectType() != null && e.getSkill().getEffectAbnormalLvl() >= 0 && e.getSkill().getEffectAbnormalLvl() <= negateLvl) || (e.getSkill().getAbnormalLvl() >= 0 && e.getSkill().getAbnormalLvl() <= negateLvl)))
- temp.add(e);
- }
- }
- }
- }
- if (!temp.isEmpty())
- {
- for (L2Effect e : temp)
- if (e != null)
- e.exit();
- }
- FastList.recycle(temp);
- }
-
- /**
- * Exits all buffs effects of the skills with "removedOnAnyAction" set.
- * Called on any action except movement (attack, cast).
- */
- public void stopEffectsOnAction()
- {
- if (_hasBuffsRemovedOnAnyAction)
- {
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e : _buffs)
- if (e != null && e.getSkill().isRemovedOnAnyActionExceptMove())
- e.exit(true);
- }
- }
- }
- }
- }
-
- public void stopEffectsOnDamage(boolean awake)
- {
- if (_hasBuffsRemovedOnDamage)
- {
- if (_buffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_buffs.isEmpty())
- {
- for (L2Effect e : _buffs)
- if (e != null
- && e.getSkill().isRemovedOnDamage()
- && (awake || e.getSkill().getSkillType() != L2SkillType.SLEEP))
- e.exit(true);
- }
- }
- }
- }
- if (_hasDebuffsRemovedOnDamage)
- {
- if (_debuffs != null)
- {
- //synchronized (_buffs)
- {
- if (!_debuffs.isEmpty())
- {
- for (L2Effect e : _debuffs)
- if (e != null
- && e.getSkill().isRemovedOnDamage()
- && (awake || e.getSkill().getSkillType() != L2SkillType.SLEEP))
- e.exit(true);
- }
- }
- }
- }
- }
-
- public void updateEffectIcons(boolean partyOnly)
- {
- if (_buffs == null && _debuffs == null)
- return;
-
- if (partyOnly)
- _partyOnly = true;
-
- queueRunner();
- }
-
- public void queueEffect(L2Effect effect, boolean remove)
- {
- if (effect == null) return;
-
- if (!_queuesInitialized)
- init();
-
- if (remove)
- _removeQueue.offer(effect);
- else
- _addQueue.offer(effect);
-
- queueRunner();
- }
-
- private synchronized void init()
- {
- if (_queuesInitialized)
- return;
- _addQueue = new LinkedBlockingQueue<L2Effect>();
- _removeQueue = new LinkedBlockingQueue<L2Effect>();
- _queuesInitialized = true;
- }
-
- private void queueRunner()
- {
- if (!queueLock.compareAndSet(false, true))
- return;
-
- try
- {
- L2Effect effect;
- do
- {
- // remove has more priority than add
- // so removing all effects from queue first
- while ((effect = _removeQueue.poll()) != null)
- {
- removeEffectFromQueue(effect);
- _partyOnly = false;
- }
-
- if ((effect = _addQueue.poll()) != null)
- {
- addEffectFromQueue(effect);
- _partyOnly = false;
- }
- }
- while (!_addQueue.isEmpty() || !_removeQueue.isEmpty());
-
- computeEffectFlags();
- updateEffectIcons();
- }
- finally
- {
- queueLock.set(false);
- }
- }
-
- protected void removeEffectFromQueue(L2Effect effect)
- {
- if (effect == null) return;
-
- FastList<L2Effect> effectList;
-
- if (effect.getSkill().isDebuff())
- {
- if (_debuffs == null)
- return;
- effectList = _debuffs;
- }
- else
- {
- if (_buffs == null)
- return;
- effectList = _buffs;
- }
-
- if ("none".equals(effect.getAbnormalType()))
- {
- // Remove Func added by this effect from the L2Character Calculator
- _owner.removeStatsOwner(effect);
- }
- else
- {
- if(_stackedEffects == null) return;
-
- // Get the list of all stacked effects corresponding to the stack type of the L2Effect to add
- List<L2Effect> stackQueue = _stackedEffects.get(effect.getAbnormalType());
-
- if (stackQueue == null || stackQueue.isEmpty()) return;
-
- int index = stackQueue.indexOf(effect);
-
- // Remove the effect from the stack group
- if (index >= 0)
- {
- stackQueue.remove(effect);
- // Check if the first stacked effect was the effect to remove
- if (index == 0)
- {
- // Remove all its Func objects from the L2Character calculator set
- _owner.removeStatsOwner(effect);
-
- // Check if there's another effect in the Stack Group
- if (!stackQueue.isEmpty())
- {
- L2Effect newStackedEffect = listsContains(stackQueue.get(0));
- if (newStackedEffect != null)
- {
- // Set the effect to In Use
- if (newStackedEffect.setInUse(true))
- // Add its list of Funcs to the Calculator set of the L2Character
- _owner.addStatFuncs(newStackedEffect.getStatFuncs());
- }
- }
- }
- if (stackQueue.isEmpty())
- _stackedEffects.remove(effect.getAbnormalType());
- else
- // Update the Stack Group table _stackedEffects of the L2Character
- _stackedEffects.put(effect.getAbnormalType(), stackQueue);
- }
- }
-
- // Remove the active skill L2effect from _effects of the L2Character
- if (effectList.remove(effect) && _owner instanceof L2PcInstance && effect.getShowIcon())
- {
- SystemMessage sm;
- if (effect.getSkill().isToggle())
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ABORTED);
- }
- else
- {
- sm = SystemMessage.getSystemMessage(SystemMessageId.EFFECT_S1_DISAPPEARED);
- }
- sm.addSkillName(effect);
- _owner.sendPacket(sm);
- }
- }
-
- protected void addEffectFromQueue(L2Effect newEffect)
- {
- if (newEffect == null) return;
-
- L2Skill newSkill = newEffect.getSkill();
-
- if (newSkill.isDebuff())
- {
- if (_debuffs == null) _debuffs = new FastList<L2Effect>().shared();
- for (L2Effect e : _debuffs)
- {
- if (e != null
- && e.getSkill().getId() == newEffect.getSkill().getId()
- && e.getEffectType() == newEffect.getEffectType()
- && e.getAbnormalLvl() == newEffect.getAbnormalLvl()
- && e.getAbnormalType().equals(newEffect.getAbnormalType()))
- {
- // Started scheduled timer needs to be canceled.
- newEffect.stopEffectTask();
- return;
- }
- }
- _debuffs.addLast(newEffect);
- }
- else
- {
- if (_buffs == null) _buffs = new FastList<L2Effect>().shared();
-
- for (L2Effect e : _buffs)
- {
- if (e != null
- && e.getSkill().getId() == newEffect.getSkill().getId()
- && e.getEffectType() == newEffect.getEffectType()
- && e.getAbnormalLvl() == newEffect.getAbnormalLvl()
- && e.getAbnormalType().equals(newEffect.getAbnormalType()))
- {
- e.exit(); // exit this
- }
- }
-
- // if max buffs, no herb effects are used, even if they would replace one old
- if (newEffect.isHerbEffect() && getBuffCount() >= _owner.getMaxBuffCount())
- {
- newEffect.stopEffectTask();
- return;
- }
-
- // Remove first buff when buff list is full
- if (!doesStack(newSkill) && !newSkill.is7Signs())
- {
- int effectsToRemove;
- if (newSkill.isDance())
- {
- effectsToRemove = getDanceCount() - Config.DANCES_MAX_AMOUNT;
- if (effectsToRemove >= 0)
- {
- for (L2Effect e : _buffs)
- {
- if (e == null || !e.getSkill().isDance())
- continue;
-
- // get first dance
- e.exit();
- effectsToRemove--;
- if (effectsToRemove < 0)
- break;
- }
- }
- }
- else
- {
- effectsToRemove = getBuffCount() - _owner.getMaxBuffCount();
- if (effectsToRemove >= 0)
- {
- switch (newSkill.getSkillType())
- {
- case BUFF:
- case HEAL_PERCENT:
- case MANAHEAL_PERCENT:
- for (L2Effect e : _buffs)
- {
- if (e == null || e.getSkill().isDance())
- continue;
-
- switch (e.getSkill().getSkillType())
- {
- case BUFF:
- case HEAL_PERCENT:
- case MANAHEAL_PERCENT:
- e.exit();
- effectsToRemove--;
- break; // break switch()
- default:
- continue; // continue for()
- }
- if (effectsToRemove < 0)
- break; // break for()
- }
- }
- }
- }
- }
-
- // Icons order: buffs, 7s, toggles, dances
- if (newSkill.isDance())
- _buffs.addLast(newEffect);
- else
- {
- int pos=0;
- if (newSkill.isToggle())
- {
- // toggle skill - before all dances
- for (L2Effect e : _buffs)
- {
- if (e == null)
- continue;
- if (e.getSkill().isDance())
- break;
- pos++;
- }
- }
- else
- {
- // normal buff - before toggles and 7s and dances
- for (L2Effect e : _buffs)
- {
- if (e == null)
- continue;
- if (e.getSkill().isToggle() || e.getSkill().is7Signs()
- || e.getSkill().isDance())
- break;
- pos++;
- }
- }
- _buffs.add(pos, newEffect);
- }
- }
-
- // Check if a stack group is defined for this effect
- if ("none".equals(newEffect.getAbnormalType()))
- {
- // Set this L2Effect to In Use
- if (newEffect.setInUse(true))
- // Add Funcs of this effect to the Calculator set of the L2Character
- _owner.addStatFuncs(newEffect.getStatFuncs());
-
- return;
- }
-
- List<L2Effect> stackQueue;
- L2Effect effectToAdd = null;
- L2Effect effectToRemove = null;
- if (_stackedEffects == null) _stackedEffects = new FastMap<String, List<L2Effect>>();
-
- // Get the list of all stacked effects corresponding to the stack type of the L2Effect to add
- stackQueue = _stackedEffects.get(newEffect.getAbnormalType());
-
- if (stackQueue != null)
- {
- int pos = 0;
- if (!stackQueue.isEmpty())
- {
- // Get the first stacked effect of the Stack group selected
- effectToRemove = listsContains(stackQueue.get(0));
-
- // Create an Iterator to go through the list of stacked effects in progress on the L2Character
- Iterator<L2Effect> queueIterator = stackQueue.iterator();
-
- while (queueIterator.hasNext())
- {
- if (newEffect.getAbnormalLvl() < queueIterator.next().getAbnormalLvl())
- pos++;
- else break;
- }
- // Add the new effect to the Stack list in function of its position in the Stack group
- stackQueue.add(pos, newEffect);
-
- // skill.exit() could be used, if the users don't wish to see "effect
- // removed" always when a timer goes off, even if the buff isn't active
- // any more (has been replaced). but then check e.g. npc hold and raid petrification.
- if (Config.EFFECT_CANCELING && !newEffect.isHerbEffect() && stackQueue.size() > 1)
- {
- if (newSkill.isDebuff())
- {
- _debuffs.remove(stackQueue.remove(1));
- }
- else
- {
- _buffs.remove(stackQueue.remove(1));
- }
- }
- }
- else
- stackQueue.add(0, newEffect);
- }
- else
- {
- stackQueue = new FastList<L2Effect>();
- stackQueue.add(0, newEffect);
- }
-
- // Update the Stack Group table _stackedEffects of the L2Character
- _stackedEffects.put(newEffect.getAbnormalType(), stackQueue);
-
- // Get the first stacked effect of the Stack group selected
- if (!stackQueue.isEmpty())
- {
- effectToAdd = listsContains(stackQueue.get(0));
- }
-
- if (effectToRemove != effectToAdd)
- {
- if (effectToRemove != null)
- {
- // Remove all Func objects corresponding to this stacked effect from the Calculator set of the L2Character
- _owner.removeStatsOwner(effectToRemove);
-
- // Set the L2Effect to Not In Use
- effectToRemove.setInUse(false);
- }
- if (effectToAdd != null)
- {
- // Set this L2Effect to In Use
- if (effectToAdd.setInUse(true))
- // Add all Func objects corresponding to this stacked effect to the Calculator set of the L2Character
- _owner.addStatFuncs(effectToAdd.getStatFuncs());
- }
- }
- }
-
- protected void updateEffectIcons()
- {
- if (_owner == null)
- return;
-
- if (!(_owner instanceof L2Playable))
- {
- updateEffectFlags();
- return;
- }
-
- AbnormalStatusUpdate mi = null;
- PartySpelled ps = null;
- ExOlympiadSpelledInfo os = null;
-
- if (_owner instanceof L2PcInstance)
- {
- if (_partyOnly)
- _partyOnly = false;
- else
- mi = new AbnormalStatusUpdate();
-
- if (_owner.isInParty())
- ps = new PartySpelled(_owner);
-
- if (((L2PcInstance)_owner).isInOlympiadMode() && ((L2PcInstance)_owner).isOlympiadStart())
- os = new ExOlympiadSpelledInfo((L2PcInstance)_owner);
- }
- else
- if (_owner instanceof L2Summon)
- ps = new PartySpelled(_owner);
-
- boolean foundRemovedOnAction = false;
- boolean foundRemovedOnDamage = false;
-
- if (_buffs != null && !_buffs.isEmpty())
- {
- //synchronized (_buffs)
- {
- for (L2Effect e : _buffs)
- {
- if (e == null)
- continue;
-
- if (e.getSkill().isRemovedOnAnyActionExceptMove())
- foundRemovedOnAction = true;
- if (e.getSkill().isRemovedOnDamage())
- foundRemovedOnDamage = true;
-
- if (!e.getShowIcon())
- continue;
-
- switch (e.getEffectType())
- {
- case CHARGE: // handled by EtcStatusUpdate
- case SIGNET_GROUND:
- continue;
- }
-
- if (e.getInUse())
- {
- if (mi != null)
- e.addIcon(mi);
-
- if (ps != null)
- e.addPartySpelledIcon(ps);
-
- if (os != null)
- e.addOlympiadSpelledIcon(os);
- }
- }
- }
- }
-
- _hasBuffsRemovedOnAnyAction = foundRemovedOnAction;
- _hasBuffsRemovedOnDamage = foundRemovedOnDamage;
- foundRemovedOnDamage = false;
-
- if (_debuffs != null && !_debuffs.isEmpty())
- {
- //synchronized (_debuffs)
- {
- for (L2Effect e : _debuffs)
- {
- if (e == null)
- continue;
-
- if (e.getSkill().isRemovedOnAnyActionExceptMove())
- foundRemovedOnAction = true;
- if (e.getSkill().isRemovedOnDamage())
- foundRemovedOnDamage = true;
-
- if (!e.getShowIcon())
- continue;
-
- switch (e.getEffectType())
- {
- case SIGNET_GROUND:
- continue;
- }
-
- if (e.getInUse())
- {
- if (mi != null)
- e.addIcon(mi);
-
- if (ps != null)
- e.addPartySpelledIcon(ps);
-
- if (os != null)
- e.addOlympiadSpelledIcon(os);
- }
- }
- }
- }
-
- _hasDebuffsRemovedOnDamage = foundRemovedOnDamage;
-
- if (mi != null)
- _owner.sendPacket(mi);
-
- if (ps != null)
- {
- if (_owner instanceof L2Summon)
- {
- L2PcInstance summonOwner = ((L2Summon)_owner).getOwner();
-
- if (summonOwner != null)
- {
- if (summonOwner.isInParty())
- summonOwner.getParty().broadcastToPartyMembers(ps);
- else
- summonOwner.sendPacket(ps);
- }
- }
- else
- if (_owner instanceof L2PcInstance && _owner.isInParty())
- _owner.getParty().broadcastToPartyMembers(ps);
- }
-
- if (os != null)
- {
- final OlympiadGameTask game = OlympiadGameManager.getInstance().getOlympiadTask(((L2PcInstance)_owner).getOlympiadGameId());
- if (game != null && game.isBattleStarted())
- game.getZone().broadcastPacketToObservers(os);
- }
- }
-
- protected void updateEffectFlags()
- {
- boolean foundRemovedOnAction = false;
- boolean foundRemovedOnDamage = false;
-
- if (_buffs != null && !_buffs.isEmpty())
- {
- //synchronized (_buffs)
- {
- for (L2Effect e : _buffs)
- {
- if (e == null)
- continue;
-
- if (e.getSkill().isRemovedOnAnyActionExceptMove())
- foundRemovedOnAction = true;
- if (e.getSkill().isRemovedOnDamage())
- foundRemovedOnDamage = true;
- }
- }
- }
- _hasBuffsRemovedOnAnyAction = foundRemovedOnAction;
- _hasBuffsRemovedOnDamage = foundRemovedOnDamage;
- foundRemovedOnDamage = false;
-
- if (_debuffs != null && !_debuffs.isEmpty())
- {
- //synchronized (_debuffs)
- {
- for (L2Effect e : _debuffs)
- {
- if (e == null)
- continue;
-
- if (e.getSkill().isRemovedOnDamage())
- foundRemovedOnDamage = true;
- }
- }
- }
- _hasDebuffsRemovedOnDamage = foundRemovedOnDamage;
- }
-
- /**
- * Returns effect if contains in _buffs or _debuffs and null if not found
- * @param effect
- * @return
- */
- private L2Effect listsContains(L2Effect effect)
- {
- if (_buffs != null && !_buffs.isEmpty()&& _buffs.contains(effect))
- return effect;
- if (_debuffs != null && !_debuffs.isEmpty() && _debuffs.contains(effect))
- return effect;
- return null;
- }
-
- /**
- * Recalculate effect bits flag.<br>
- * Please no concurrency access
- */
- private final void computeEffectFlags()
- {
- int flags = 0;
-
- if (_buffs != null)
- {
- for (L2Effect e : _buffs)
- {
- if (e == null)
- continue;
- flags |= e.getEffectFlags();
- }
- }
-
- if (_debuffs != null)
- {
- for (L2Effect e : _debuffs)
- {
- if (e == null)
- continue;
- flags |= e.getEffectFlags();
- }
- }
- _effectFlags = flags;
- }
-
- /**
- * Check if target is affected with special buff
- * @param bitFlag flag of special buff
- * @return boolean true if affected
- */
- public boolean isAffected(int bitFlag)
- {
- return (_effectFlags & bitFlag) != 0;
- }
-
- /**
- * Clear and null all queues and lists
- * Use only during delete character from the world.
- */
- public void clear()
- {
- try
- {
- if (_addQueue != null)
- {
- _addQueue.clear();
- _addQueue = null;
- }
- if (_removeQueue != null)
- {
- _removeQueue.clear();
- _removeQueue = null;
- }
- _queuesInitialized = false;
-
- if (_buffs != null)
- {
- _buffs.clear();
- _buffs = null;
- }
- if (_debuffs != null)
- {
- _debuffs.clear();
- _debuffs = null;
- }
-
- if (_stackedEffects != null)
- {
- _stackedEffects.clear();
- _stackedEffects = null;
- }
- }
- catch (Exception e)
- {
- _log.log(Level.WARNING, "", e);
- }
- }
- }
|