AttackableAI stream removal.
This commit is contained in:
parent
86e7ccd169
commit
d0466f8b01
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,11 +21,10 @@ import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
|
|||||||
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
import static org.l2jmobius.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Comparator;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import org.l2jmobius.Config;
|
import org.l2jmobius.Config;
|
||||||
import org.l2jmobius.commons.util.Rnd;
|
import org.l2jmobius.commons.util.Rnd;
|
||||||
@ -1131,35 +1130,64 @@ public class AttackableAI extends CreatureAI
|
|||||||
|
|
||||||
// Check current target first.
|
// Check current target first.
|
||||||
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
final int range = insideCastRange ? skill.getCastRange() + getActiveChar().getTemplate().getCollisionRadius() : 2000; // TODO need some forget range
|
||||||
Stream<Creature> stream;
|
|
||||||
|
final List<Creature> result = new ArrayList<>();
|
||||||
if (isBad)
|
if (isBad)
|
||||||
{
|
{
|
||||||
//@formatter:off
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
stream = npc.getAggroList().values().stream()
|
{
|
||||||
.map(AggroInfo::getAttacker)
|
if (checkSkillTarget(skill, aggro.getAttacker()))
|
||||||
.filter(c -> checkSkillTarget(skill, c))
|
{
|
||||||
.sorted(Comparator.<Creature>comparingInt(npc::getHating).reversed());
|
result.add(aggro.getAttacker());
|
||||||
//@formatter:on
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stream = World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range, c -> checkSkillTarget(skill, c)).stream();
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, range))
|
||||||
|
{
|
||||||
|
if (checkSkillTarget(skill, creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
// Maybe add self to the list of targets since getVisibleObjects doesn't return yourself.
|
||||||
if (checkSkillTarget(skill, npc))
|
if (checkSkillTarget(skill, npc))
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, Stream.of(npc));
|
result.add(npc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For heal skills sort by hp missing.
|
// For heal skills sort by hp missing.
|
||||||
if (skill.hasEffectType(EffectType.HEAL))
|
if (skill.hasEffectType(EffectType.HEAL))
|
||||||
{
|
{
|
||||||
stream = stream.sorted(Comparator.comparingInt(Creature::getCurrentHpPercent));
|
int searchValue = Integer.MAX_VALUE;
|
||||||
|
Creature creature = null;
|
||||||
|
|
||||||
|
for (Creature c : result)
|
||||||
|
{
|
||||||
|
final int hpPer = c.getCurrentHpPercent();
|
||||||
|
if (hpPer < searchValue)
|
||||||
|
{
|
||||||
|
searchValue = hpPer;
|
||||||
|
creature = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creature != null)
|
||||||
|
{
|
||||||
|
return creature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any target.
|
// Return any target.
|
||||||
return stream.findFirst().orElse(null);
|
if (!result.isEmpty())
|
||||||
|
{
|
||||||
|
return result.get(Rnd.get(result.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Creature targetReconsider(boolean randomTarget)
|
private Creature targetReconsider(boolean randomTarget)
|
||||||
@ -1167,24 +1195,57 @@ public class AttackableAI extends CreatureAI
|
|||||||
final Attackable npc = getActiveChar();
|
final Attackable npc = getActiveChar();
|
||||||
if (randomTarget)
|
if (randomTarget)
|
||||||
{
|
{
|
||||||
Stream<Creature> stream = npc.getAggroList().values().stream().map(AggroInfo::getAttacker).filter(this::checkTarget);
|
final List<Creature> result = new ArrayList<>();
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
if (checkTarget(aggro.getAttacker()))
|
||||||
|
{
|
||||||
|
result.add(aggro.getAttacker());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If npc is aggressive, add characters within aggro range too
|
// If npc is aggressive, add characters within aggro range too.
|
||||||
if (npc.isAggressive())
|
if (npc.isAggressive())
|
||||||
{
|
{
|
||||||
stream = Stream.concat(stream, World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream());
|
for (Creature creature : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(creature))
|
||||||
|
{
|
||||||
|
result.add(creature);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return stream.findAny().orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//@formatter:off
|
if (!result.isEmpty())
|
||||||
return npc.getAggroList().values().stream()
|
{
|
||||||
.filter(a -> checkTarget(a.getAttacker()))
|
return result.get(Rnd.get(result.size()));
|
||||||
.sorted(Comparator.comparingInt(AggroInfo::getHate))
|
}
|
||||||
.map(AggroInfo::getAttacker)
|
}
|
||||||
.findFirst()
|
|
||||||
.orElse(npc.isAggressive() ? World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange(), this::checkTarget).stream().findAny().orElse(null) : null);
|
int searchValue = Integer.MIN_VALUE;
|
||||||
//@formatter:on
|
Creature creature = null;
|
||||||
|
for (AggroInfo aggro : npc.getAggroList().values())
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
if (checkTarget(aggro.getAttacker()) && (aggro.getHate() > searchValue))
|
||||||
|
{
|
||||||
|
searchValue = aggro.getHate();
|
||||||
|
creature = aggro.getAttacker();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((creature == null) && npc.isAggressive())
|
||||||
|
{
|
||||||
|
for (Creature nearby : World.getInstance().getVisibleObjectsInRange(npc, Creature.class, npc.getAggroRange()))
|
||||||
|
{
|
||||||
|
if (checkTarget(nearby))
|
||||||
|
{
|
||||||
|
return nearby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user