Чисто вот как пример - AI для нпс, на время своего существования создающий вокруг себя круглую зону с листенером, который при входе в эту зону вешает определенный скилл, а при выходе - снимает его.
Я таких нпс юзаю для работы тотемов дающих бафф, ну тех что можно юзать у Антараса/Валакаса.
package ai;
import l2p.commons.collections.StatsSet;
import l2p.commons.geometry.Circle;
import l2p.gameserver.ai.DefaultAI;
import l2p.gameserver.data.holder.SkillHolder;
import l2p.gameserver.enums.ZoneType;
import l2p.gameserver.holders.world.ZoneTemplate;
import l2p.gameserver.listener.zone.OnZoneEnterLeaveListener;
import l2p.gameserver.model.Creature;
import l2p.gameserver.model.Territory;
import l2p.gameserver.model.World;
import l2p.gameserver.model.Zone;
import l2p.gameserver.model.instances.NpcInstance;
import l2p.gameserver.model.skills.Skill;
import l2p.gameserver.utils.Strings;
/**
* AI, создающее на время круглую зону, при вхождении в которую на игроков накладывается заданное умение, а при выходе - снимается.
* Радиус зоны берется из накладываемого умения.
*
* @author Gaikotsu
*/
public class CastSkillZone extends DefaultAI
{
private Skill _skill = null;
private Zone _zone = null;
private ZoneListener _listener = null;
public CastSkillZone(NpcInstance actor)
{
super(actor);
}
@Override
public boolean isGlobalAI()
{
return true;
}
@Override
protected void onEvtSpawn()
{
super.onEvtSpawn();
NpcInstance actor = getActor();
i_ai0 = actor.getParameter("lifeTime", 0);
i_ai1 = actor.getParameter("castPeriod", 0);
addTimer(1001, i_ai0 * 1000L);
addTimer(1002, i_ai1 * 1000L);
String[] skill = actor.getParameter("castSkill", "0,0").split(",");
if (skill.length != 2)
return;
_skill = SkillHolder.getInstance().getSkill(Integer.valueOf(skill[0]), Integer.valueOf(skill[1]));
if (_skill == null)
return;
int radius = _skill.getAffectRange();
Circle c = new Circle(actor.getLoc(), radius);
int z = actor.getLoc().getZ();
c.setMaxZ(z + radius);
c.setMinZ(z - radius);
StatsSet set = new StatsSet();
set.set("name", Strings.EMPTY);
set.set("type", ZoneType.dummy);
set.set("territory", new Territory().add(c));
_listener = new ZoneListener();
_zone = new Zone(new ZoneTemplate(set));
_zone.setReflection(actor.getReflection());
_zone.addListener(_listener);
_zone.setActive(true);
}
@Override
public void onEvtDespawn()
{
super.onEvtDespawn();
_zone.setActive(false);
_zone.removeListener(_listener);
_zone = null;
}
@Override
protected void onEvtTimer(int timerId, Object arg1, Object arg2)
{
NpcInstance actor = getActor();
if (actor == null)
return;
if (timerId == 1001)
{
actor.deleteMe();
}
else if (timerId == 1002)
{
if (_skill == null)
return;
World.getAroundPlayables(actor, _skill.getAffectRange(), _skill.getAffectRange()).stream().filter(cha -> cha != null && !cha.isDead()).forEach(cha -> _skill.getEffects(actor, cha, false));
addTimer(1002, i_ai1 * 1000L);
}
}
private class ZoneListener implements OnZoneEnterLeaveListener
{
@Override
public void onEnter(Zone zone, Creature actor)
{
if (!actor.isPlayable())
return;
if (actor.getEffectList().checkEffectsBySkill(_skill))
return;
_skill.getEffects(getActor(), actor, false);
}
@Override
public void onLeave(Zone zone, Creature actor)
{
if (!actor.isPlayable())
return;
if (!actor.getEffectList().checkEffectsBySkill(_skill))
return;
actor.getEffectList().stopEffect(_skill);
}
}
}