Abnormal improvements.

This commit is contained in:
MobiusDev
2018-11-01 16:51:03 +00:00
parent bd7da50452
commit d35a9d46ec
90 changed files with 929 additions and 1632 deletions

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -786,7 +786,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,13 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -37,20 +35,12 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
@@ -62,17 +52,6 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime()); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
} }
} }
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
// packet.writeH(0x00); // Sub level
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
}
}
return true; return true;
} }
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,40 +23,12 @@ import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final Skill skill = info.getSkill();
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_skillId = skill.getDisplayId();
_level = skill.getDisplayLevel();
// _subLevel = skill.getSubLevel();
_abnormalType = skill.getAbnormalType().getClientId();
_duration = skill.isAura() ? -1 : info.getTime();
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -68,7 +39,6 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse) .filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle()) .filter(b -> !b.getSkill().isToggle())
.map(Effect::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -81,13 +51,15 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._abnormalType); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._duration); packet.writeH(info.getSkill().getAbnormalType().getClientId());
packet.writeD(info._caster); // writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeH(info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -786,7 +786,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,13 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -37,20 +35,12 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
@@ -62,17 +52,6 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime()); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
} }
} }
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeH(0x00); // Sub level
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
}
}
return true; return true;
} }
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,41 +23,12 @@ import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final Skill skill = info.getSkill();
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_skillId = skill.getDisplayId();
_level = skill.getDisplayLevel();
_subLevel = skill.getSubLevel();
_abnormalType = skill.getAbnormalType().getClientId();
_duration = skill.isAura() ? -1 : info.getTime();
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -69,7 +39,6 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse) .filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle()) .filter(b -> !b.getSkill().isToggle())
.map(Effect::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -82,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -786,7 +786,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,13 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -37,20 +35,12 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
@@ -62,17 +52,6 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime()); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
} }
} }
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeH(0x00); // Sub level
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
}
}
return true; return true;
} }
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,41 +23,12 @@ import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final Skill skill = info.getSkill();
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_skillId = skill.getDisplayId();
_level = skill.getDisplayLevel();
_subLevel = skill.getSubLevel();
_abnormalType = skill.getAbnormalType().getClientId();
_duration = skill.isAura() ? -1 : info.getTime();
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -69,7 +39,6 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse) .filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle()) .filter(b -> !b.getSkill().isToggle())
.map(Effect::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -82,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -786,7 +786,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,13 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -37,20 +35,12 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
@@ -62,17 +52,6 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime()); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
} }
} }
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeH(0x00); // Sub level
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
}
}
return true; return true;
} }
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,41 +23,12 @@ import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final Skill skill = info.getSkill();
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_skillId = skill.getDisplayId();
_level = skill.getDisplayLevel();
_subLevel = skill.getSubLevel();
_abnormalType = skill.getAbnormalType().getClientId();
_duration = skill.isAura() ? -1 : info.getTime();
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -69,7 +39,6 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse) .filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle()) .filter(b -> !b.getSkill().isToggle())
.map(Effect::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -82,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -786,7 +786,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,13 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -37,20 +35,12 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
@@ -62,17 +52,6 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime()); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
} }
} }
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeH(0x00); // Sub level
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
}
}
return true; return true;
} }
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,41 +23,12 @@ import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final Skill skill = info.getSkill();
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_skillId = skill.getDisplayId();
_level = skill.getDisplayLevel();
_subLevel = skill.getSubLevel();
_abnormalType = skill.getAbnormalType().getClientId();
_duration = skill.isAura() ? -1 : info.getTime();
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -69,7 +39,6 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse) .filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle()) .filter(b -> !b.getSkill().isToggle())
.map(Effect::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -82,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -786,7 +786,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,13 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -37,20 +35,12 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
@@ -62,17 +52,6 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime()); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
} }
} }
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeH(0x00); // Sub level
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
}
}
return true; return true;
} }
} }

View File

@@ -16,7 +16,6 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -24,41 +23,12 @@ import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final Skill skill = info.getSkill();
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_skillId = skill.getDisplayId();
_level = skill.getDisplayLevel();
_subLevel = skill.getSubLevel();
_abnormalType = skill.getAbnormalType().getClientId();
_duration = skill.isAura() ? -1 : info.getTime();
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -69,7 +39,6 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse) .filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle()) .filter(b -> !b.getSkill().isToggle())
.map(Effect::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -82,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -776,7 +776,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,17 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author Mobius
* @version Classic 2.0
*/
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -41,38 +35,21 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
{ {
packet.writeD(info.getSkill().getDisplayId()); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info.getSkill().getDisplayLevel()); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeD(0x00); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info.getSkill().isAura() ? -1 : info.getTime()); packet.writeD(info.getSkill().getAbnormalType().getClientId());
} writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
}
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
} }
} }
return true; return true;

View File

@@ -16,8 +16,8 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
@@ -25,35 +25,10 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author proGenitor <br>
* Experimental packet compatible for L2Classic 2.0.
*/
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -61,7 +36,9 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
_character = character; _character = character;
_effects = character.getEffectList().getEffects() _effects = character.getEffectList().getEffects()
.stream() .stream()
.map(Effect::new) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle())
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -74,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -776,7 +776,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,17 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author Mobius
* @version Classic 2.0
*/
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -41,38 +35,21 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
{ {
packet.writeD(info.getSkill().getDisplayId()); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info.getSkill().getDisplayLevel()); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeD(0x00); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info.getSkill().isAura() ? -1 : info.getTime()); packet.writeD(info.getSkill().getAbnormalType().getClientId());
} writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
}
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
} }
} }
return true; return true;

View File

@@ -16,8 +16,8 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
@@ -25,35 +25,10 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author proGenitor <br>
* Experimental packet compatible for L2Classic 2.0.
*/
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -61,7 +36,9 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
_character = character; _character = character;
_effects = character.getEffectList().getEffects() _effects = character.getEffectList().getEffects()
.stream() .stream()
.map(Effect::new) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle())
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -74,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -776,7 +776,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,17 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author Mobius
* @version Classic 2.0
*/
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -41,38 +35,21 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
{ {
packet.writeD(info.getSkill().getDisplayId()); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info.getSkill().getDisplayLevel()); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeD(0x00); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info.getSkill().isAura() ? -1 : info.getTime()); packet.writeD(info.getSkill().getAbnormalType().getClientId());
} writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
}
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
} }
} }
return true; return true;

View File

@@ -16,8 +16,8 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
@@ -25,35 +25,10 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author proGenitor <br>
* Experimental packet compatible for L2Classic 2.0.
*/
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -61,7 +36,9 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
_character = character; _character = character;
_effects = character.getEffectList().getEffects() _effects = character.getEffectList().getEffects()
.stream() .stream()
.map(Effect::new) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle())
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -74,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }

View File

@@ -16,6 +16,8 @@
*/ */
package handlers.effecthandlers; package handlers.effecthandlers;
import java.util.Collections;
import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet; import com.l2jmobius.gameserver.model.StatsSet;
@@ -38,6 +40,19 @@ public final class CallSkillOnActionTime extends AbstractEffect
setTicks(params.getInt("ticks")); setTicks(params.getInt("ticks"));
} }
@Override
public void onStart(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().stopEffects(Collections.singleton(_skill.getSkill().getAbnormalType()));
effected.getEffectList().addBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override
public void onExit(L2Character effector, L2Character effected, Skill skill)
{
effected.getEffectList().removeBlockedAbnormalTypes(Collections.singleton(_skill.getSkill().getAbnormalType()));
}
@Override @Override
public boolean onActionTime(L2Character effector, L2Character effected, Skill skill) public boolean onActionTime(L2Character effector, L2Character effected, Skill skill)
{ {

View File

@@ -136,6 +136,5 @@ public final class Disarmor extends AbstractEffect
} }
} }
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -84,6 +84,5 @@ public final class DoubleCast extends AbstractEffect
return null; return null;
}); });
} }
super.onExit(effector, effected, skill);
} }
} }

View File

@@ -65,15 +65,15 @@ public final class CharEffectList
{ {
private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName()); private static final Logger LOGGER = Logger.getLogger(CharEffectList.class.getName());
/** Queue containing all effects from buffs for this effect list. */ /** Queue containing all effects from buffs for this effect list. */
private volatile Queue<BuffInfo> _actives; private volatile Queue<BuffInfo> _actives = new ConcurrentLinkedQueue<>();
/** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all passives for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _passives; private volatile Set<BuffInfo> _passives = ConcurrentHashMap.newKeySet();
/** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */ /** List containing all options for this effect list. They bypass most of the actions and they are not included in most operations. */
private volatile Set<BuffInfo> _options; private volatile Set<BuffInfo> _options = ConcurrentHashMap.newKeySet();
/** Map containing the all stacked effect in progress for each {@code AbnormalType}. */ /** Map containing the all stacked effect in progress for each {@code AbnormalType}. */
private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class); private volatile Set<AbnormalType> _stackedEffects = EnumSet.noneOf(AbnormalType.class);
/** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */ /** Set containing all {@code AbnormalType}s that shouldn't be added to this creature effect list. */
private volatile Set<AbnormalType> _blockedAbnormalTypes = null; private volatile Set<AbnormalType> _blockedAbnormalTypes = EnumSet.noneOf(AbnormalType.class);
/** Set containing all abnormal visual effects this creature currently displays. */ /** Set containing all abnormal visual effects this creature currently displays. */
private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class); private volatile Set<AbnormalVisualEffect> _abnormalVisualEffects = EnumSet.noneOf(AbnormalVisualEffect.class);
/** Short buff skill ID. */ /** Short buff skill ID. */
@@ -110,7 +110,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getPassives() public Set<BuffInfo> getPassives()
{ {
return _passives != null ? Collections.unmodifiableSet(_passives) : Collections.emptySet(); return Collections.unmodifiableSet(_passives);
} }
/** /**
@@ -119,7 +119,7 @@ public final class CharEffectList
*/ */
public Set<BuffInfo> getOptions() public Set<BuffInfo> getOptions()
{ {
return _options != null ? Collections.unmodifiableSet(_options) : Collections.emptySet(); return Collections.unmodifiableSet(_options);
} }
/** /**
@@ -128,7 +128,7 @@ public final class CharEffectList
*/ */
public Collection<BuffInfo> getEffects() public Collection<BuffInfo> getEffects()
{ {
return _actives != null ? Collections.unmodifiableCollection(_actives) : Collections.emptyList(); return Collections.unmodifiableCollection(_actives);
} }
/** /**
@@ -137,7 +137,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getBuffs() public List<BuffInfo> getBuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> !b.getSkill().getBuffType().isBuff()).collect(Collectors.toList());
} }
/** /**
@@ -146,7 +146,7 @@ public final class CharEffectList
*/ */
public List<BuffInfo> getDebuffs() public List<BuffInfo> getDebuffs()
{ {
return _actives != null ? _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList()) : Collections.emptyList(); return _actives.stream().filter(b -> b.getSkill().isDebuff()).collect(Collectors.toList());
} }
/** /**
@@ -156,7 +156,7 @@ public final class CharEffectList
*/ */
public boolean isAffectedBySkill(int skillId) public boolean isAffectedBySkill(int skillId)
{ {
return ((_actives != null) && _actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || ((_passives != null) && _passives.stream().anyMatch(i -> i.getSkill().getId() == skillId)); return (_actives.stream().anyMatch(i -> i.getSkill().getId() == skillId)) || (_passives.stream().anyMatch(i -> i.getSkill().getId() == skillId));
} }
/** /**
@@ -166,7 +166,7 @@ public final class CharEffectList
*/ */
public BuffInfo getBuffInfoBySkillId(int skillId) public BuffInfo getBuffInfoBySkillId(int skillId)
{ {
return Stream.concat(_actives != null ? _actives.stream() : Stream.empty(), _passives != null ? _passives.stream() : Stream.empty()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null); return Stream.concat(_actives.stream(), _passives.stream()).filter(b -> b.getSkill().getId() == skillId).findFirst().orElse(null);
} }
/** /**
@@ -216,18 +216,6 @@ public final class CharEffectList
*/ */
public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes) public void addBlockedAbnormalTypes(Set<AbnormalType> blockedAbnormalTypes)
{ {
// Initialize
if (_blockedAbnormalTypes == null)
{
synchronized (this)
{
if (_blockedAbnormalTypes == null)
{
_blockedAbnormalTypes = EnumSet.copyOf(blockedAbnormalTypes);
}
}
}
_blockedAbnormalTypes.addAll(blockedAbnormalTypes); _blockedAbnormalTypes.addAll(blockedAbnormalTypes);
} }
@@ -238,7 +226,7 @@ public final class CharEffectList
*/ */
public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots) public boolean removeBlockedAbnormalTypes(Set<AbnormalType> blockedBuffSlots)
{ {
return (_blockedAbnormalTypes != null) && _blockedAbnormalTypes.removeAll(blockedBuffSlots); return _blockedAbnormalTypes.removeAll(blockedBuffSlots);
} }
/** /**
@@ -247,7 +235,7 @@ public final class CharEffectList
*/ */
public Set<AbnormalType> getBlockedAbnormalTypes() public Set<AbnormalType> getBlockedAbnormalTypes()
{ {
return _blockedAbnormalTypes != null ? Collections.unmodifiableSet(_blockedAbnormalTypes) : Collections.emptySet(); return Collections.unmodifiableSet(_blockedAbnormalTypes);
} }
/** /**
@@ -277,7 +265,7 @@ public final class CharEffectList
*/ */
public int getBuffCount() public int getBuffCount()
{ {
return _actives != null ? (_buffCount.get() - _hiddenBuffs.get()) : 0; return !_actives.isEmpty() ? (_buffCount.get() - _hiddenBuffs.get()) : 0;
} }
/** /**
@@ -374,7 +362,7 @@ public final class CharEffectList
*/ */
public void stopAllPassives(boolean update, boolean broadcast) public void stopAllPassives(boolean update, boolean broadcast)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.forEach(this::remove); _passives.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -392,7 +380,7 @@ public final class CharEffectList
*/ */
public void stopAllOptions(boolean update, boolean broadcast) public void stopAllOptions(boolean update, boolean broadcast)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.forEach(this::remove); _options.forEach(this::remove);
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -490,7 +478,7 @@ public final class CharEffectList
*/ */
public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast) public void stopEffects(Predicate<BuffInfo> filter, boolean update, boolean broadcast)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
_actives.stream().filter(filter).forEach(this::remove); _actives.stream().filter(filter).forEach(this::remove);
@@ -678,6 +666,10 @@ public final class CharEffectList
{ {
// Remove active effect. // Remove active effect.
removeActive(info, removed); removeActive(info, removed);
if (_owner.isNpc()) // Fix for all NPC debuff animations removed.
{
updateEffectList(broadcast);
}
} }
// Update stats, effect flags and icons. // Update stats, effect flags and icons.
@@ -693,7 +685,7 @@ public final class CharEffectList
*/ */
private synchronized void removeActive(BuffInfo info, boolean removed) private synchronized void removeActive(BuffInfo info, boolean removed)
{ {
if (_actives != null) if (!_actives.isEmpty())
{ {
// Removes the buff from the given effect list. // Removes the buff from the given effect list.
_actives.remove(info); _actives.remove(info);
@@ -716,7 +708,7 @@ public final class CharEffectList
private void removePassive(BuffInfo info, boolean removed) private void removePassive(BuffInfo info, boolean removed)
{ {
if (_passives != null) if (!_passives.isEmpty())
{ {
_passives.remove(info); _passives.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -725,7 +717,7 @@ public final class CharEffectList
private void removeOption(BuffInfo info, boolean removed) private void removeOption(BuffInfo info, boolean removed)
{ {
if (_options != null) if (!_options.isEmpty())
{ {
_options.remove(info); _options.remove(info);
info.stopAllEffects(removed); info.stopAllEffects(removed);
@@ -821,12 +813,6 @@ public final class CharEffectList
} }
} }
// Initialize
if (_actives == null)
{
_actives = new ConcurrentLinkedQueue<>();
}
// Manage effect stacking. // Manage effect stacking.
if (hasAbnormalType(skill.getAbnormalType())) if (hasAbnormalType(skill.getAbnormalType()))
{ {
@@ -857,7 +843,7 @@ public final class CharEffectList
} }
else else
{ {
// Remove effect that gets overriden. // Remove effect that gets overridden.
remove(existingInfo); remove(existingInfo);
} }
} }
@@ -865,7 +851,7 @@ public final class CharEffectList
{ {
info.setInUse(false); info.setInUse(false);
} }
else // The effect we try to add should be overriden. else // The effect we try to add should be overridden.
{ {
return; return;
} }
@@ -918,18 +904,6 @@ public final class CharEffectList
return; return;
} }
// Initialize
if (_passives == null)
{
synchronized (this)
{
if (_passives == null)
{
_passives = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous passives of this id. // Remove previous passives of this id.
_passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b -> _passives.stream().filter(Objects::nonNull).filter(b -> b.getSkill().getId() == skill.getId()).forEach(b ->
{ {
@@ -947,18 +921,6 @@ public final class CharEffectList
{ {
if (info.getOption() != null) if (info.getOption() != null)
{ {
// Initialize
if (_options == null)
{
synchronized (this)
{
if (_options == null)
{
_options = ConcurrentHashMap.newKeySet();
}
}
}
// Remove previous options of this id. // Remove previous options of this id.
_options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b -> _options.stream().filter(Objects::nonNull).filter(b -> b.getOption().getId() == info.getOption().getId()).forEach(b ->
{ {
@@ -988,7 +950,7 @@ public final class CharEffectList
final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty(); final Optional<PartySpelled> ps = ((party != null) || _owner.isSummon()) ? Optional.of(new PartySpelled(_owner)) : Optional.empty();
final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty(); final Optional<ExOlympiadSpelledInfo> os = (player.isInOlympiadMode() && player.isOlympiadStart()) ? Optional.of(new ExOlympiadSpelledInfo(player)) : Optional.empty();
if (_actives != null) if (!_actives.isEmpty())
{ {
//@formatter:off //@formatter:off
_actives.stream() _actives.stream()
@@ -1109,42 +1071,47 @@ public final class CharEffectList
final Set<BuffInfo> unhideBuffs = new HashSet<>(); final Set<BuffInfo> unhideBuffs = new HashSet<>();
// Recalculate new flags // Recalculate new flags
if (_actives != null) for (BuffInfo info : _actives)
{ {
for (BuffInfo info : _actives) if (info != null)
{ {
if (info != null) final Skill skill = info.getSkill();
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
final Skill skill = info.getSkill(); // If incoming buff isnt hidden, remove any hidden buffs with its abnormal type.
if (info.isInUse())
// Handle hidden buffs. Check if there was such abnormal before so we can continue.
if ((_hiddenBuffs.get() > 0) && _stackedEffects.contains(skill.getAbnormalType()))
{ {
// If incoming buff isnt hidden, remove any hidden buffs with its abnormal type. unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
if (info.isInUse())
{
unhideBuffs.removeIf(b -> b.isAbnormalType(skill.getAbnormalType()));
}
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
{
unhideBuffs.add(info);
}
} }
// If this incoming buff is hidden and its first of its abnormal, or it removes any previous hidden buff with the same or lower abnormal level and add this instead.
// Add the EffectType flag. else if (!abnormalTypeFlags.contains(skill.getAbnormalType()) || unhideBuffs.removeIf(b -> (b.isAbnormalType(skill.getAbnormalType())) && (b.getSkill().getAbnormalLvl() <= skill.getAbnormalLvl())))
for (AbstractEffect e : info.getEffects())
{ {
flags |= e.getEffectFlags(); unhideBuffs.add(info);
} }
}
// Add the AbnormalType flag. // Add the EffectType flag.
abnormalTypeFlags.add(skill.getAbnormalType()); for (AbstractEffect e : info.getEffects())
{
flags |= e.getEffectFlags();
}
// Add AbnormalVisualEffect flag. // Add the AbnormalType flag.
if (skill.hasAbnormalVisualEffects()) abnormalTypeFlags.add(skill.getAbnormalType());
// Add AbnormalVisualEffect flag.
if (skill.hasAbnormalVisualEffects())
{
for (AbnormalVisualEffect ave : skill.getAbnormalVisualEffects())
{ {
abnormalVisualEffectFlags.addAll(skill.getAbnormalVisualEffects()); abnormalVisualEffectFlags.add(ave);
_abnormalVisualEffects.add(ave);
}
if (broadcast)
{
_owner.updateAbnormalVisualEffects();
} }
} }
} }
@@ -1167,7 +1134,7 @@ public final class CharEffectList
if (broadcast) if (broadcast)
{ {
// Check if there is change in AbnormalVisualEffect // Check if there is change in AbnormalVisualEffect
if ((abnormalVisualEffectFlags.size() != _abnormalVisualEffects.size()) || !abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects)) if (!abnormalVisualEffectFlags.containsAll(_abnormalVisualEffects))
{ {
_abnormalVisualEffects = abnormalVisualEffectFlags; _abnormalVisualEffects = abnormalVisualEffectFlags;
_owner.updateAbnormalVisualEffects(); _owner.updateAbnormalVisualEffects();

View File

@@ -77,7 +77,6 @@ public class DoppelgangerInstance extends L2Npc
info.setAbnormalTime(summonerInfo.getAbnormalTime()); info.setAbnormalTime(summonerInfo.getAbnormalTime());
getEffectList().add(info); getEffectList().add(info);
} }
} }
} }
} }

View File

@@ -776,7 +776,7 @@ public class CharStat
final CharEffectList effectList = _activeChar.getEffectList(); final CharEffectList effectList = _activeChar.getEffectList();
final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar)); final Stream<BuffInfo> passives = effectList.getPassives().stream().filter(BuffInfo::isInUse).filter(info -> info.getSkill().checkConditions(SkillConditionScope.PASSIVE, _activeChar, _activeChar));
final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse); final Stream<BuffInfo> options = effectList.getOptions().stream().filter(BuffInfo::isInUse);
final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives != null ? passives : Stream.empty(), options != null ? options : Stream.empty())); final Stream<BuffInfo> effectsStream = Stream.concat(effectList.getEffects().stream().filter(BuffInfo::isInUse), Stream.concat(passives, options));
// Call pump to each effect // Call pump to each effect
//@formatter:off //@formatter:off

View File

@@ -389,10 +389,10 @@ public final class BuffInfo
for (AbstractEffect effect : _effects) for (AbstractEffect effect : _effects)
{ {
// Instant effects shouldn't call onExit(..). // Instant effects shouldn't call onExit(..).
if (!effect.isInstant()) // if (!effect.isInstant())
{ // {
effect.onExit(_effector, _effected, _skill); effect.onExit(_effector, _effected, _skill);
} // }
} }
// Set the proper system message. // Set the proper system message.

View File

@@ -21,17 +21,11 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author Mobius
* @version Classic 2.0
*/
public class AbnormalStatusUpdate implements IClientOutgoingPacket public class AbnormalStatusUpdate implements IClientOutgoingPacket
{ {
private final List<BuffInfo> _effects = new ArrayList<>(); private final List<BuffInfo> _effects = new ArrayList<>();
private final List<Skill> _effects2 = new ArrayList<>();
public void addSkill(BuffInfo info) public void addSkill(BuffInfo info)
{ {
@@ -41,38 +35,21 @@ public class AbnormalStatusUpdate implements IClientOutgoingPacket
} }
} }
public void addSkill(Skill skill)
{
if (!skill.isHealingPotionSkill())
{
_effects2.add(skill);
}
}
@Override @Override
public boolean write(PacketWriter packet) public boolean write(PacketWriter packet)
{ {
OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet); OutgoingPackets.ABNORMAL_STATUS_UPDATE.writeId(packet);
packet.writeH(_effects.size() + _effects2.size()); packet.writeH(_effects.size());
for (BuffInfo info : _effects) for (BuffInfo info : _effects)
{ {
if ((info != null) && info.isInUse()) if ((info != null) && info.isInUse())
{ {
packet.writeD(info.getSkill().getDisplayId()); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info.getSkill().getDisplayLevel()); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeD(0x00); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info.getSkill().isAura() ? -1 : info.getTime()); packet.writeD(info.getSkill().getAbnormalType().getClientId());
} writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
}
for (Skill skill : _effects2)
{
if (skill != null)
{
packet.writeD(skill.getDisplayId());
packet.writeH(skill.getDisplayLevel());
packet.writeD(skill.getAbnormalType().getClientId());
packet.writeH(-1);
} }
} }
return true; return true;

View File

@@ -16,8 +16,8 @@
*/ */
package com.l2jmobius.gameserver.network.serverpackets; package com.l2jmobius.gameserver.network.serverpackets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.commons.network.PacketWriter;
@@ -25,35 +25,10 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.skills.BuffInfo; import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.network.OutgoingPackets; import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author proGenitor <br>
* Experimental packet compatible for L2Classic 2.0.
*/
public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
{ {
private final L2Character _character; private final L2Character _character;
private List<Effect> _effects = new ArrayList<>(); private final List<BuffInfo> _effects;
private static class Effect
{
protected int _skillId;
protected int _level;
protected int _subLevel;
protected int _abnormalType;
protected int _duration;
protected int _caster;
public Effect(BuffInfo info)
{
final L2Character caster = info.getEffector();
int casterId = 0;
if (caster != null)
{
casterId = caster.getObjectId();
}
_caster = casterId;
}
}
public ExAbnormalStatusUpdateFromTarget(L2Character character) public ExAbnormalStatusUpdateFromTarget(L2Character character)
{ {
@@ -61,7 +36,9 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
_character = character; _character = character;
_effects = character.getEffectList().getEffects() _effects = character.getEffectList().getEffects()
.stream() .stream()
.map(Effect::new) .filter(Objects::nonNull)
.filter(BuffInfo::isInUse)
.filter(b -> !b.getSkill().isToggle())
.collect(Collectors.toList()); .collect(Collectors.toList());
//@formatter:on //@formatter:on
} }
@@ -74,14 +51,14 @@ public class ExAbnormalStatusUpdateFromTarget implements IClientOutgoingPacket
packet.writeD(_character.getObjectId()); packet.writeD(_character.getObjectId());
packet.writeH(_effects.size()); packet.writeH(_effects.size());
for (Effect info : _effects) for (BuffInfo info : _effects)
{ {
packet.writeD(info._skillId); packet.writeD(info.getSkill().getDisplayId());
packet.writeH(info._level); packet.writeH(info.getSkill().getDisplayLevel());
packet.writeH(info._subLevel); // packet.writeH(info.getSkill().getSubLevel());
packet.writeH(info._abnormalType); packet.writeH(info.getSkill().getAbnormalType().getClientId());
writeOptionalD(packet, info._duration); writeOptionalD(packet, info.getSkill().isAura() ? -1 : info.getTime());
packet.writeD(info._caster); packet.writeD(info.getEffectorObjectId());
} }
return true; return true;
} }