Привет!
Где-то месяц назад решил попробовать реализовать криво-косо агатионов под Interlude. Сейчас вернулся к этой теме, написал кастомное расширение, которое работает с одни большим "НО", всё прекрасно работает на одном игроке на сервере, но если их двое, то всё ломается, поэтому, можно сказать, что ничего не работает.
Предлагаю совместно допилить эту историю, если такое возможно, потому что многим админам серверов Interlude эта тема интересна.
Внимание! Я вообще не программист, от слова "совсем", код, скорее всего, не профессионален даже на 50%, просто пробую реализовать задуманное, поэтому прошу относиться с пониманием
Дополнительно прикладываю скомпиленное расширение, чтобы можно было попробовать, как это работает
Где-то месяц назад решил попробовать реализовать криво-косо агатионов под Interlude. Сейчас вернулся к этой теме, написал кастомное расширение, которое работает с одни большим "НО", всё прекрасно работает на одном игроке на сервере, но если их двое, то всё ломается, поэтому, можно сказать, что ничего не работает.
Предлагаю совместно допилить эту историю, если такое возможно, потому что многим админам серверов Interlude эта тема интересна.
Внимание! Я вообще не программист, от слова "совсем", код, скорее всего, не профессионален даже на 50%, просто пробую реализовать задуманное, поэтому прошу относиться с пониманием
Java:
package Simple;
import l2.commons.threading.RunnableImpl;
import l2.gameserver.ThreadPoolManager;
import l2.gameserver.listener.actor.OnMagicUseListener;
import l2.gameserver.listener.actor.npc.OnSpawnListener;
import l2.gameserver.listener.actor.player.OnPlayerEnterListener;
import l2.gameserver.listener.actor.player.OnPlayerExitListener;
import l2.gameserver.listener.actor.player.OnTeleportListener;
import l2.gameserver.listener.inventory.OnEquipListener;
import l2.gameserver.model.Creature;
import l2.gameserver.model.Playable;
import l2.gameserver.model.Player;
import l2.gameserver.model.Skill;
import l2.gameserver.model.actor.listener.NpcListenerList;
import l2.gameserver.model.actor.listener.PlayerListenerList;
import l2.gameserver.model.entity.Reflection;
import l2.gameserver.model.instances.NpcInstance;
import l2.gameserver.model.items.ItemInstance;
import l2.gameserver.scripts.ScriptFile;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
public class SimpleCode implements ScriptFile {
public agathion a;
@Override
public void onLoad() {
PlayerListenerList.addGlobal(new OnPlayerEnterListener() {
@Override
public void onPlayerEnter(Player player) {
a = new agathion(player);
a.setHasAgathion(false);
a.getData().forEach((dItem, dSkill) -> {
if(a.getPlayer().getAllSkills().stream().anyMatch(s -> s.getId() == dSkill)) {
a.setDataSkill(dSkill);
a.setDataItem(dItem);
}
});
if(a.getPlayer().getAllSkills().stream().anyMatch(s -> s.getId() == 100012)) {
a.setSummonSkill(a.getPlayer().getKnownSkill(a.getDataSkill()));
a.setUnSummonSkill(a.getPlayer().getKnownSkill(100012));
a.getPlayer().addUnActiveSkill(a.getUnSummonSkill());
}
a.getPlayer().getInventory().addListener(new OnEquipListener() {
@Override
public void onEquip(int i, ItemInstance itemInstance, Playable playable) {
if(a.getData().containsKey(itemInstance.getItemId())) {
a.setDataItem(itemInstance.getItemId());
a.setDataSkill(a.getData().get(a.getDataItem()));
if (!a.getHasAgathion()) {
a.setSummonSkill(a.getPlayer().getKnownSkill(a.getDataSkill()));
a.setUnSummonSkill(a.getPlayer().getKnownSkill(100012));
a.getPlayer().addUnActiveSkill(a.getUnSummonSkill());
}
}
}
@Override
public void onUnequip(int i, ItemInstance itemInstance, Playable playable) {
if(itemInstance.getItemId() == a.getDataItem() && a.getHasAgathion()) {
a.getAgathionNpc().deleteMe();
a.setHasAgathion(false);
a.getPlayer().removeUnActiveSkill(a.getSummonSkill());
a.getPlayer().addUnActiveSkill(a.getUnSummonSkill());
}
}
});
}
});
PlayerListenerList.addGlobal(new OnMagicUseListener() {
@Override
public void onMagicUse(Creature creature, Skill skill, Creature creature1, boolean b) {
a.agathionSpawn(skill);
}
});
PlayerListenerList.addGlobal(new OnTeleportListener() {
@Override
public void onTeleport(Player player, int i, int i1, int i2, Reflection reflection) {
if (a.getHasAgathion())
a.teleportAgathion(a.getAgathionNpc(), i, i1, i2);
}
});
PlayerListenerList.addGlobal(new OnPlayerExitListener() {
@Override
public void onPlayerExit(Player player) {
if (a.getHasAgathion())
a.deleteAgathion(a.getAgathionNpc());
}
});
}
@Override
public void onReload() { }
@Override
public void onShutdown() { }
private static class agathion {
private final Player player;
private NpcInstance agathionNpc;
private boolean hasAgathion;
private Skill summonSkill;
private Skill unSummonSkill;
private final HashMap<Integer, Integer> data = new HashMap<Integer, Integer>();
private int dataSkill;
private int dataItem;
private agathion(Player p) {
data.put(9411, 100000);
data.put(9412, 100001);
data.put(9413, 100002);
data.put(9414, 100003);
data.put(9415, 100004);
data.put(9416, 100005);
data.put(9417, 100006);
data.put(9418, 100007);
data.put(9419, 100008);
data.put(9420, 100009);
data.put(9421, 100010);
data.put(9422, 100011);
this.player = p;
}
public void agathionSpawn(Skill s) {
if(s == this.getSummonSkill()) {
NpcListenerList.addGlobal(new OnSpawnListener() {
@Override
public void onSpawn(NpcInstance npcInstance) {
if(npcInstance.getNpcId() == summonSkill.getNpcId()) {
agathionNpc = npcInstance;
hasAgathion = true;
System.out.println(player);
player.removeUnActiveSkill(unSummonSkill);
player.addUnActiveSkill(summonSkill);
ThreadPoolManager.getInstance().schedule(new agathionFollow(player, agathionNpc), 250L);
}
}
});
}
if(s == this.getUnSummonSkill()) {
this.setHasAgathion(false);
this.deleteAgathion(this.getAgathionNpc());
player.removeUnActiveSkill(this.getSummonSkill());
player.addUnActiveSkill(this.getUnSummonSkill());
}
}
public void deleteAgathion(@NotNull NpcInstance n) { n.deleteMe(); }
public void teleportAgathion(@NotNull NpcInstance n, int x, int y, int z) { n.teleToLocation(x, y, z); }
public boolean getHasAgathion() { return this.hasAgathion; }
public void setHasAgathion(boolean b) { this.hasAgathion = b; }
public NpcInstance getAgathionNpc() { return this.agathionNpc; }
public void setAgathionNpc(NpcInstance n) { this.agathionNpc = n; }
public Skill getSummonSkill() { return this.summonSkill; }
public void setSummonSkill(Skill s) { this.summonSkill = s; }
public Skill getUnSummonSkill() { return this.unSummonSkill; }
public void setUnSummonSkill(Skill s) { this.unSummonSkill = s; }
public HashMap<Integer, Integer> getData() { return this.data; }
public int getDataSkill() { return this.dataSkill; }
public void setDataSkill(int i) { dataSkill = i; }
public int getDataItem() { return this.dataItem; }
public void setDataItem(int i) { dataItem = i; }
public Player getPlayer() { return this.player; }
}
private static class agathionFollow extends RunnableImpl {
private final Player player;
private final NpcInstance agathion;
private agathionFollow(Player p, NpcInstance n) {
this.player = p;
this.agathion = n;
}
public void runImpl() {
this.agathion.moveToRelative(this.player, 5, 10);
ThreadPoolManager.getInstance().schedule(this, 250L);
}
}
}
Физически агатионы реализованы через NPC, есть item'ы (armor, не etcitem) с эквипом в слот HEAD, персонаж одевает item в установленный слот, получает дополнительные умения - призыв и отпуск агатиона.
Получается: каждый агатион - npc, item, skills
Получается: каждый агатион - npc, item, skills
- Необходимо, чтобы дудка (item) одевался на персонажа для получения дополнительных характеристик, даже не призывая агатиона, если создавать etcitem, то такая реализация будет невозможной
- Необходимо будет убирать у агатиона рамку призванного питомца, с такой задачей не смог справиться, не нашел ни единого упоминания подобного метода ни в server.jar, ни в script.jar библиотеках
- Необходимо реализовать агатиона таким образом, чтобы на него никто не агрился и его нельзя было взять в таргет абсолютно никаким образом, с таргетом еще более менее решаемо, хоть параметр TargetEnabled не работает, возможно выставить collision_height и collision_radius на значение 0.01, как это реализовано у NPC "Christmas Tree" (13006), но с агром мобов на NPC вопрос не решается, если NPC выступает в роли саммона/питомца
Дополнительно прикладываю скомпиленное расширение, чтобы можно было попробовать, как это работает