diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-01.html b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-01.html
new file mode 100644
index 0000000000..3ee28bf004
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-01.html
@@ -0,0 +1,10 @@
+
Event Manager Bonnie:
+Hey, you! You're right, I'm talking you!
+Do you know we have a new problem? It's Keber!
+ He threatens to Aden.
+ They say Keber and his lackeys appear
+ every hour on the Plains of Glory, War-Torn Plains and in the Silent Valley.
+If you defeat Keber and his servants, you can get Talisman of Aden.
+ I can teleport you to the villain. Do to want to go?
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-02.html b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-02.html
new file mode 100644
index 0000000000..3a380c5703
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-02.html
@@ -0,0 +1,6 @@
+Event Manager Bonnie:
+If you don't have time to get to the destination by yourself, I can teleport you. Of course, it's not for free. Where do to want to go?
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-03.html b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-03.html
new file mode 100644
index 0000000000..4e078090d4
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-03.html
@@ -0,0 +1,3 @@
+Event Manager Bonnie:
+Good luck! I hope you will defeat Keber.
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-04.html b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-04.html
new file mode 100644
index 0000000000..0f19a8307f
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/34216-04.html
@@ -0,0 +1,3 @@
+Event Manager Bonnie:
+You don't have enough adena. Check your pockets once again!
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/BattleWithKeber.java b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/BattleWithKeber.java
new file mode 100644
index 0000000000..6dfc634d48
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/BattleWithKeber.java
@@ -0,0 +1,494 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package events.BattleWithKeber;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.l2jmobius.gameserver.data.xml.SpawnData;
+import org.l2jmobius.gameserver.model.Location;
+import org.l2jmobius.gameserver.model.World;
+import org.l2jmobius.gameserver.model.WorldObject;
+import org.l2jmobius.gameserver.model.actor.Npc;
+import org.l2jmobius.gameserver.model.actor.Player;
+import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
+import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
+import org.l2jmobius.gameserver.model.spawns.SpawnGroup;
+import org.l2jmobius.gameserver.model.spawns.SpawnTemplate;
+import org.l2jmobius.gameserver.network.NpcStringId;
+import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
+import org.l2jmobius.gameserver.util.Broadcast;
+
+/**
+ * @author Index
+ */
+public class BattleWithKeber extends LongTimeEvent
+{
+ // NPCs
+ private static final int BONNIE = 34216;
+ private static final int KEBER_SEAL_STONE = 18551;
+ // Locations from Bonnie teleport
+ private static final Location PLAINS_OF_GLORY_TELEPORT = new Location(133994, 7136, -4352);
+ private static final Location WAR_TORN_PLAINS_TELEPORT = new Location(161658, 21299, -3672);
+ private static final Location SILENT_VALLEY_TELEPORT = new Location(181645, 52823, -6112);
+ // Spawn locations for monsters
+ private static final Location PLAINS_OF_GLORY_BOSS = new Location(132573, 7865, -4300);
+ private static final Location WAR_TORN_PLAINS_BOSS = new Location(161205, 21680, -3680);
+ private static final Location SILENT_VALLEY_BOSS = new Location(180640, 52824, -6096);
+ // Monsters
+ private static final int KEBER_LOW = 18537; // 63
+ private static final int KEBER_MIDDLE = 18552; // 69
+ private static final int KEBER_HIGH = 18553; // 75
+ private static final int KISHAN = 18538; // 63
+ private static final int NOMA = 18542; // 69
+ private static final int SPALL = 18546; // 75
+ private static final Set BOSSES = new HashSet<>();
+ static
+ {
+ BOSSES.add(KEBER_LOW);
+ BOSSES.add(KEBER_MIDDLE);
+ BOSSES.add(KEBER_HIGH);
+ BOSSES.add(KISHAN);
+ BOSSES.add(NOMA);
+ BOSSES.add(SPALL);
+ }
+ private static final List NORMAL_MINIONS = new ArrayList<>();
+ static
+ {
+ NORMAL_MINIONS.add(18539);
+ NORMAL_MINIONS.add(18543);
+ NORMAL_MINIONS.add(18547);
+ }
+ private static final List ELITE_MINIONS = new ArrayList<>();
+ static
+ {
+ ELITE_MINIONS.add(18540);
+ ELITE_MINIONS.add(18544);
+ ELITE_MINIONS.add(18548);
+ }
+ private static final List BRAINWASHED_MINIONS = new ArrayList<>();
+ static
+ {
+ BRAINWASHED_MINIONS.add(18541);
+ BRAINWASHED_MINIONS.add(18545);
+ BRAINWASHED_MINIONS.add(18549);
+ }
+ // Drop
+ private static final Set KEBER_LOW_DROP = new HashSet<>();
+ static
+ {
+ KEBER_LOW_DROP.add(new ItemChanceHolder(57, 100, 525000)); // Adena x525000
+ KEBER_LOW_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x2
+ KEBER_LOW_DROP.add(new ItemChanceHolder(94481, 100, 150)); // Clan XP x150
+ }
+ private static final Set KEBER_MIDDLE_DROP = new HashSet<>();
+ static
+ {
+ KEBER_MIDDLE_DROP.add(new ItemChanceHolder(57, 100, 725000)); // Adena 725000
+ KEBER_MIDDLE_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x2
+ KEBER_MIDDLE_DROP.add(new ItemChanceHolder(94481, 100, 150)); // Clan XP x150
+ }
+ private static final Set KEBER_HIGH_DROP = new HashSet<>();
+ static
+ {
+ KEBER_HIGH_DROP.add(new ItemChanceHolder(57, 100, 925000)); // Adena x925000
+ KEBER_HIGH_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x2
+ KEBER_HIGH_DROP.add(new ItemChanceHolder(94481, 100, 150)); // Clan XP x150
+ }
+ private static final Set KISHAN_DROP = new HashSet<>();
+ static
+ {
+ KISHAN_DROP.add(new ItemChanceHolder(57, 100, 45000)); // Adena x45000
+ KISHAN_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x1
+ KISHAN_DROP.add(new ItemChanceHolder(94481, 100, 50)); // Clan XP x50
+ }
+ private static final Set NOMA_DROP = new HashSet<>();
+ static
+ {
+ NOMA_DROP.add(new ItemChanceHolder(57, 100, 55000)); // Adena x55000
+ NOMA_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x1
+ NOMA_DROP.add(new ItemChanceHolder(94481, 100, 50)); // Clan XP x50
+ }
+ private static final Set SPALL_DROP = new HashSet<>();
+ static
+ {
+ SPALL_DROP.add(new ItemChanceHolder(57, 100, 65000)); // Adena x55000
+ SPALL_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x1
+ SPALL_DROP.add(new ItemChanceHolder(94481, 100, 50)); // Clan XP x50
+ }
+ private static final Set MINION_DROP = new HashSet<>();
+ static
+ {
+ MINION_DROP.add(new ItemChanceHolder(91767, 10, 1)); // Enchant Kit: Talisman of Aden x1
+ }
+ private static final Map> NPC_DROP = new HashMap<>();
+ static
+ {
+ NPC_DROP.put(KEBER_LOW, KEBER_LOW_DROP);
+ NPC_DROP.put(KEBER_MIDDLE, KEBER_MIDDLE_DROP);
+ NPC_DROP.put(KEBER_HIGH, KEBER_HIGH_DROP);
+ NPC_DROP.put(KISHAN, KISHAN_DROP);
+ NPC_DROP.put(NOMA, NOMA_DROP);
+ NPC_DROP.put(SPALL, SPALL_DROP);
+ }
+ // Misc
+ private static final int EVENT_MESSAGE_START = -1;
+ private static final int EVENT_MESSAGE_KILL = -2;
+ private static final int EVENT_MESSAGE_TO_KILLER = -3;
+ private static final int EVENT_MESSAGE_WEAK = -4;
+ private static final int ELITE_MONSTER_COUNT = 200;
+ private static final int BRAINWASHED_MONSTER_COUNT = 100;
+ private static final int PLAINS_OF_GLORY_TELEPORT_COST = 2000;
+ private static final int WAR_TORN_PLAINS_TELEPORT_COST = 2500;
+ private static final int SILENT_VALLEY_TELEPORT_COST = 3000;
+ private static final Map BROADCAST_MESSAGES = new HashMap<>();
+ static
+ {
+ BROADCAST_MESSAGES.put(KEBER_LOW, NpcStringId.AHEM_YOU_DARE_TO_BOTHER_KEBER_YOU_WILL_SEE_NO_MERCY);
+ BROADCAST_MESSAGES.put(KEBER_MIDDLE, NpcStringId.AHEM_YOU_DARE_TO_BOTHER_KEBER_YOU_WILL_SEE_NO_MERCY);
+ BROADCAST_MESSAGES.put(KEBER_HIGH, NpcStringId.AHEM_YOU_DARE_TO_BOTHER_KEBER_YOU_WILL_SEE_NO_MERCY);
+ BROADCAST_MESSAGES.put(KISHAN, NpcStringId.KISHAN_MY_SERVANT_ATTACK);
+ BROADCAST_MESSAGES.put(NOMA, NpcStringId.NOMA_MY_SERVANT_ATTACK);
+ BROADCAST_MESSAGES.put(SPALL, NpcStringId.SPALL_MY_SERVANT_ATTACK);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_START, NpcStringId.MAKE_THE_SACRED_BLOOD_SACRIFICE_TO_KEBER_ATTACK);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_KILL, NpcStringId.AH_YOU_ARE_INDEED_STRONG_S1_I_HAVE_TO_RETREAT_THIS_TIME);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_TO_KILLER, NpcStringId.YOU_WILL_NOT_BE_FORGIVEN_I_WILL_BE_BACK_AND_YOU_LL_REGRET_IT);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_WEAK, NpcStringId.LOOKS_LIKE_YOU_RE_WAY_TOO_WEAK_TO_BEAT_ME);
+ }
+ private static final AtomicIntegerArray MINION_KILL_COUNTER = new AtomicIntegerArray(3);
+ private static final AtomicReference SPAWN_TEMPLATE = new AtomicReference<>();
+ private static final AtomicIntegerArray MINION_MAX_COUNT = new AtomicIntegerArray(3);
+
+ private BattleWithKeber()
+ {
+ if (isEventPeriod())
+ {
+ addFirstTalkId(BONNIE);
+ addTalkId(BONNIE);
+ addKillId(KEBER_LOW, KEBER_MIDDLE, KEBER_HIGH, KISHAN, NOMA, SPALL);
+ addKillId(NORMAL_MINIONS);
+ addKillId(ELITE_MINIONS);
+ addKillId(BRAINWASHED_MINIONS);
+ addSpawnId(KEBER_LOW, KEBER_MIDDLE, KEBER_HIGH, KISHAN, NOMA, SPALL);
+ addSpawnId(NORMAL_MINIONS);
+ addSpawnId(ELITE_MINIONS);
+ startQuestTimer("KEBER_EVENT_START", getMsTimeForEventStage(1), null, null);
+ SPAWN_TEMPLATE.set(SpawnData.getInstance().getSpawns().stream().filter(t -> t.getName() != null).filter(t -> t.getName().contains("KEBER_MINIONS")).findAny().orElse(null));
+ if (SPAWN_TEMPLATE.get() != null)
+ {
+ MINION_MAX_COUNT.set(0, SPAWN_TEMPLATE.get().getGroups().stream().filter(g -> ((g.getName() != null) && g.getName().equalsIgnoreCase("KISHAN"))).findFirst().get().getSpawns().stream().findFirst().get().getCount());
+ MINION_MAX_COUNT.set(1, SPAWN_TEMPLATE.get().getGroups().stream().filter(g -> ((g.getName() != null) && g.getName().equalsIgnoreCase("NOMA"))).findFirst().get().getSpawns().stream().findFirst().get().getCount());
+ MINION_MAX_COUNT.set(2, SPAWN_TEMPLATE.get().getGroups().stream().filter(g -> ((g.getName() != null) && g.getName().equalsIgnoreCase("SPALL"))).findFirst().get().getSpawns().stream().findFirst().get().getCount());
+ }
+ }
+ }
+
+ @Override
+ public String onAdvEvent(String event, Npc npc, Player player)
+ {
+ switch (event)
+ {
+ case "34216-02.html":
+ {
+ String html = getHtm(player, "34216-02.html");
+ html = html.replace("%n1%", String.valueOf(PLAINS_OF_GLORY_TELEPORT_COST));
+ html = html.replace("%n2%", String.valueOf(WAR_TORN_PLAINS_TELEPORT_COST));
+ html = html.replace("%n3%", String.valueOf(SILENT_VALLEY_TELEPORT_COST));
+ return html;
+ }
+ case "TELEPORT_01":
+ case "TELEPORT_02":
+ case "TELEPORT_03":
+ {
+ final byte requestLocation = Byte.parseByte(event.replace("TELEPORT_0", ""));
+ if (player.getAdena() < (requestLocation == 1 ? PLAINS_OF_GLORY_TELEPORT_COST : requestLocation == 2 ? WAR_TORN_PLAINS_TELEPORT_COST : SILENT_VALLEY_TELEPORT_COST))
+ {
+ return "34216-04.html";
+ }
+ player.teleToLocation((requestLocation == 1 ? PLAINS_OF_GLORY_TELEPORT : requestLocation == 2 ? WAR_TORN_PLAINS_TELEPORT : SILENT_VALLEY_TELEPORT));
+ return "34216-03.html";
+ }
+ case "KEBER_EVENT_START":
+ {
+ for (Npc wo : World.getInstance().getVisibleObjects(player, Npc.class))
+ {
+ if (wo.getId() == KEBER_SEAL_STONE)
+ {
+ wo.setDisplayEffect(1);
+ Broadcast.toKnownPlayers((wo), new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_START), ExShowScreenMessage.TOP_CENTER, 5000));
+ }
+ }
+ MINION_KILL_COUNTER.set(0, 0);
+ MINION_KILL_COUNTER.set(1, 0);
+ MINION_KILL_COUNTER.set(2, 0);
+ SPAWN_TEMPLATE.get().getGroups().forEach(SpawnGroup::spawnAll);
+ cancelQuestTimer("KEBER_EVENT_START", null, null);
+ startQuestTimer("KEBER_EVENT_BOSS_STAGE", getMsTimeForEventStage(2), null, null);
+ break;
+ }
+ case "KEBER_EVENT_BOSS_STAGE":
+ {
+ changeNpcSpawn(3, false, false);
+ for (int fieldType = 0; fieldType < 3; fieldType++)
+ {
+ final int summonedBossId = (getRandomBoolean() ? (fieldType == 0 ? KEBER_LOW : fieldType == 1 ? KEBER_MIDDLE : KEBER_HIGH) : (fieldType == 0 ? KISHAN : fieldType == 1 ? NOMA : SPALL));
+ final Location spawnLoc = (fieldType == 0 ? PLAINS_OF_GLORY_BOSS : fieldType == 1 ? WAR_TORN_PLAINS_BOSS : SILENT_VALLEY_BOSS);
+ addSpawn(summonedBossId, spawnLoc, false, 5 * 60 * 1000); // 5 minutes
+ }
+ cancelQuestTimer("KEBER_EVENT_BOSS_STAGE", null, null);
+ startQuestTimer("KEBER_EVENT_END", getMsTimeForEventStage(3), null, null);
+ break;
+ }
+ case "KEBER_EVENT_END":
+ {
+ for (Npc wo : World.getInstance().getVisibleObjects(player, Npc.class))
+ {
+ if (wo.getId() == KEBER_SEAL_STONE)
+ {
+ wo.setDisplayEffect(2); // remove effect
+ for (Npc boss : World.getInstance().getVisibleObjects((wo), Npc.class))
+ {
+ if (BOSSES.contains(boss.getId()) && !boss.isAlikeDead())
+ {
+ Broadcast.toKnownPlayers((wo), new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_WEAK), ExShowScreenMessage.TOP_CENTER, 5000));
+ break;
+ }
+ }
+ }
+ }
+ cancelQuestTimer("KEBER_EVENT_END", null, null);
+ startQuestTimer("KEBER_EVENT_START", getMsTimeForEventStage(1), null, null);
+ changeNpcSpawn(3, true, true);
+ break;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String onFirstTalk(Npc npc, Player player)
+ {
+ return "34216-01.html";
+ }
+
+ @Override
+ public String onSpawn(Npc npc)
+ {
+ final int type = getFieldType(npc.getId());
+ final boolean eventIsPending = (getQuestTimer("KEBER_EVENT_START", null, null) != null) && getQuestTimer("KEBER_EVENT_START", null, null).isActive();
+ final boolean eventOnBossStage = (getQuestTimer("KEBER_EVENT_END", null, null) != null) && getQuestTimer("KEBER_EVENT_END", null, null).isActive();
+ if ((type != -1) && (npc.getId() == NORMAL_MINIONS.get(type)))
+ {
+ if (eventIsPending || eventOnBossStage)
+ {
+ npc.getSpawn().stopRespawn();
+ npc.deleteMe();
+ return super.onSpawn(npc);
+ }
+
+ final int eliteMonsterId = ELITE_MINIONS.get(type);
+ final int brainWashedMonsterId = BRAINWASHED_MINIONS.get(type);
+ final int nearbyMonstersCount = World.getInstance().getVisibleObjects(npc, Npc.class).stream().filter(nearby -> ((nearby.getId() == NORMAL_MINIONS.get(type)) || (nearby.getId() == eliteMonsterId) || (nearby.getId() == brainWashedMonsterId))).toList().size();
+ final int maxSpawnMonsters = MINION_MAX_COUNT.length() == 0 ? 0 : MINION_MAX_COUNT.get(type);
+ if (nearbyMonstersCount >= maxSpawnMonsters)
+ {
+ npc.deleteMe();
+ return super.onSpawn(npc);
+ }
+ final int killedCount = MINION_KILL_COUNTER.get(type);
+ if (killedCount >= (ELITE_MONSTER_COUNT + BRAINWASHED_MONSTER_COUNT))
+ {
+ addSpawn(brainWashedMonsterId, npc.getLocation());
+ npc.deleteMe();
+ }
+ else if (killedCount >= ELITE_MONSTER_COUNT)
+ {
+ addSpawn(eliteMonsterId, npc.getLocation());
+ npc.deleteMe();
+ }
+ }
+ else if (BOSSES.contains(npc.getId()))
+ {
+ // Broadcast to nearby players string which says "monster respawn"
+ Broadcast.toKnownPlayers(npc, new ExShowScreenMessage(BROADCAST_MESSAGES.get(npc.getId()), ExShowScreenMessage.TOP_CENTER, 5000));
+ World.getInstance().getVisibleObjects(npc, Player.class).stream().findAny().ifPresent(player -> addAttackPlayerDesire(npc, player));
+ }
+ return super.onSpawn(npc);
+ }
+
+ @Override
+ public String onKill(Npc npc, Player killer, boolean isSummon)
+ {
+ if (NORMAL_MINIONS.contains(npc.getId()) || ELITE_MINIONS.contains(npc.getId()))
+ {
+ final int type = getFieldType(npc.getId());
+ int count = MINION_KILL_COUNTER.get(type);
+ if ((count >= ELITE_MONSTER_COUNT) && ELITE_MINIONS.contains(npc.getId()))
+ {
+ MINION_KILL_COUNTER.addAndGet(type, 1);
+ }
+ else if (count < ELITE_MONSTER_COUNT)
+ {
+ MINION_KILL_COUNTER.addAndGet(type, 1);
+ }
+ }
+ else
+ {
+ final Set monsterDrop = ((npc.getTemplate().getLevel() > (killer.getLevel() - 15)) && (npc.getTemplate().getLevel() < (killer.getLevel() + 15))) ? NPC_DROP.getOrDefault(npc.getId(), MINION_DROP) : new HashSet<>();
+ for (ItemChanceHolder drop : monsterDrop)
+ {
+ if (getRandom(100) < drop.getChance())
+ {
+ if ((drop.getId() == 94481) && (killer.getClan() != null)) // Avoid to get clan points as item.
+ {
+ killer.getClan().addExp(killer.getObjectId(), (int) drop.getCount());
+ }
+ else
+ {
+ killer.addItem(_eventName, drop.getId(), drop.getCount(), null, true);
+ }
+ }
+ }
+ if (BOSSES.contains(npc.getId()))
+ {
+ changeNpcSpawn(getFieldType(npc.getId()), true, false);
+ Broadcast.toKnownPlayers(killer, new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_KILL), ExShowScreenMessage.TOP_CENTER, 10000, killer.getName()));
+ killer.sendPacket(new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_TO_KILLER), ExShowScreenMessage.TOP_CENTER, 5000));
+ for (Npc crystal : World.getInstance().getVisibleObjects(npc, Npc.class))
+ {
+ if (crystal.getId() == KEBER_SEAL_STONE)
+ {
+ crystal.setDisplayEffect(2);
+ break;
+ }
+ }
+ }
+ }
+ return super.onKill(npc, killer, isSummon);
+ }
+
+ private long getMsTimeForEventStage(int type)
+ {
+ final Calendar returnTime = Calendar.getInstance();
+ final long currentTime = System.currentTimeMillis();
+ returnTime.set(Calendar.MILLISECOND, 0);
+ returnTime.set(Calendar.SECOND, 0);
+ if (type == 1)
+ {
+ returnTime.set(Calendar.MINUTE, 0);
+ returnTime.add(Calendar.HOUR_OF_DAY, 1);
+ }
+ else if (type == 2)
+ {
+ returnTime.add(Calendar.MINUTE, 10);
+ }
+ else if (type == 3)
+ {
+ returnTime.add(Calendar.MINUTE, 5);
+ }
+ if (returnTime.getTimeInMillis() < currentTime)
+ {
+ returnTime.add(Calendar.DAY_OF_YEAR, 1);
+ }
+ return returnTime.getTimeInMillis() - currentTime;
+ }
+
+ /**
+ * Because value is set and we know all ids, it can be used to get fast access to any field monster.
+ * @param npcId
+ * @return 0 - Plains, 1 - War-Torn, 2 - Silent Valley
+ */
+ private int getFieldType(int npcId)
+ {
+ if ((npcId == KEBER_LOW) || (npcId == KISHAN) || (npcId == NORMAL_MINIONS.get(0)) || (npcId == ELITE_MINIONS.get(0)) || (npcId == BRAINWASHED_MINIONS.get(0)))
+ {
+ return 0;
+ }
+ else if ((npcId == KEBER_MIDDLE) || (npcId == NOMA) || (npcId == NORMAL_MINIONS.get(1)) || (npcId == ELITE_MINIONS.get(1)) || (npcId == BRAINWASHED_MINIONS.get(1)))
+ {
+ return 1;
+ }
+ else if ((npcId == KEBER_HIGH) || (npcId == SPALL) || (npcId == NORMAL_MINIONS.get(2)) || (npcId == ELITE_MINIONS.get(2)) || (npcId == BRAINWASHED_MINIONS.get(2)))
+ {
+ return 2;
+ }
+ return -1;
+ }
+
+ private void changeNpcSpawn(int type, boolean delete, boolean removeAll)
+ {
+ if (removeAll)
+ {
+ SPAWN_TEMPLATE.get().getGroups().forEach(SpawnGroup::despawnAll);
+ }
+
+ for (WorldObject wo : World.getInstance().getVisibleObjects())
+ {
+ if (!wo.isMonster())
+ {
+ continue;
+ }
+
+ if (((type == 0) || (type == 3)) //
+ && ((!removeAll && (NORMAL_MINIONS.get(0) == wo.getId())) //
+ || (ELITE_MINIONS.get(0) == wo.getId()) //
+ || (BRAINWASHED_MINIONS.get(0) == wo.getId()) //
+ || (removeAll && ((KISHAN == wo.getId()) || (KEBER_LOW == wo.getId())))))
+ {
+ removeSpawn(wo, delete);
+ }
+ if (((type == 1) || (type == 3)) //
+ && ((!removeAll && (NORMAL_MINIONS.get(1) == wo.getId())) //
+ || (ELITE_MINIONS.get(1) == wo.getId()) //
+ || (BRAINWASHED_MINIONS.get(1) == wo.getId()) //
+ || (removeAll && ((NOMA == wo.getId()) || (KEBER_MIDDLE == wo.getId())))))
+ {
+ removeSpawn(wo, delete);
+ }
+ if (((type == 2) || (type == 3)) //
+ && ((!removeAll && (NORMAL_MINIONS.get(2) == wo.getId())) //
+ || (ELITE_MINIONS.get(2) == wo.getId()) //
+ || (BRAINWASHED_MINIONS.get(2) == wo.getId()) //
+ || (removeAll && ((SPALL == wo.getId()) || (KEBER_HIGH == wo.getId())))))
+ {
+ removeSpawn(wo, delete);
+ }
+ }
+ }
+
+ private void removeSpawn(WorldObject wo, boolean delete)
+ {
+ final Npc npc = ((Npc) wo);
+ npc.getSpawn().stopRespawn();
+ if (delete && (!BOSSES.contains(npc.getTemplate().getId()) || !npc.isAlikeDead()))
+ {
+ npc.deleteMe();
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ new BattleWithKeber();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/config.xml b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/config.xml
new file mode 100644
index 0000000000..9de724646b
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/scripts/events/BattleWithKeber/config.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/spawns/Event/BattleWithKeber.xml b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/spawns/Event/BattleWithKeber.xml
new file mode 100644
index 0000000000..2da5f42b64
--- /dev/null
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/spawns/Event/BattleWithKeber.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/18500-18599.xml b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/18500-18599.xml
index 56e27dbc0d..4df9b23a09 100644
--- a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/18500-18599.xml
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/18500-18599.xml
@@ -1141,6 +1141,10 @@
+
+
+
+
@@ -1168,6 +1172,10 @@
+
+
+
+
@@ -1190,6 +1198,9 @@
+
+
+
@@ -1211,6 +1222,10 @@
+
+
+
+
@@ -1238,6 +1253,10 @@
+
+
+
+
@@ -1264,6 +1283,10 @@
+
+
+
+
@@ -1286,6 +1309,9 @@
+
+
+
@@ -1307,6 +1333,10 @@
+
+
+
+
@@ -1333,6 +1363,10 @@
+
+
+
+
@@ -1359,6 +1393,10 @@
+
+
+
+
@@ -1380,6 +1418,9 @@
+
+
+
@@ -1400,8 +1441,7 @@
-
-
+
ETC
MALE
@@ -1415,11 +1455,14 @@
600
-
+
+
+
+
@@ -1441,6 +1484,10 @@
+
+
+
+
@@ -1462,6 +1509,10 @@
+
+
+
+
diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/34200-34299.xml b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/34200-34299.xml
index f89462d367..7f0d097ed7 100644
--- a/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/34200-34299.xml
+++ b/L2J_Mobius_Essence_6.1_BattleChronicle/dist/game/data/stats/npcs/34200-34299.xml
@@ -431,13 +431,13 @@
-
+
-
+
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-01.html b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-01.html
new file mode 100644
index 0000000000..3ee28bf004
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-01.html
@@ -0,0 +1,10 @@
+Event Manager Bonnie:
+Hey, you! You're right, I'm talking you!
+Do you know we have a new problem? It's Keber!
+ He threatens to Aden.
+ They say Keber and his lackeys appear
+ every hour on the Plains of Glory, War-Torn Plains and in the Silent Valley.
+If you defeat Keber and his servants, you can get Talisman of Aden.
+ I can teleport you to the villain. Do to want to go?
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-02.html b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-02.html
new file mode 100644
index 0000000000..3a380c5703
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-02.html
@@ -0,0 +1,6 @@
+Event Manager Bonnie:
+If you don't have time to get to the destination by yourself, I can teleport you. Of course, it's not for free. Where do to want to go?
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-03.html b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-03.html
new file mode 100644
index 0000000000..4e078090d4
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-03.html
@@ -0,0 +1,3 @@
+Event Manager Bonnie:
+Good luck! I hope you will defeat Keber.
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-04.html b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-04.html
new file mode 100644
index 0000000000..0f19a8307f
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/34216-04.html
@@ -0,0 +1,3 @@
+Event Manager Bonnie:
+You don't have enough adena. Check your pockets once again!
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/BattleWithKeber.java b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/BattleWithKeber.java
new file mode 100644
index 0000000000..6dfc634d48
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/BattleWithKeber.java
@@ -0,0 +1,494 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package events.BattleWithKeber;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.l2jmobius.gameserver.data.xml.SpawnData;
+import org.l2jmobius.gameserver.model.Location;
+import org.l2jmobius.gameserver.model.World;
+import org.l2jmobius.gameserver.model.WorldObject;
+import org.l2jmobius.gameserver.model.actor.Npc;
+import org.l2jmobius.gameserver.model.actor.Player;
+import org.l2jmobius.gameserver.model.holders.ItemChanceHolder;
+import org.l2jmobius.gameserver.model.quest.LongTimeEvent;
+import org.l2jmobius.gameserver.model.spawns.SpawnGroup;
+import org.l2jmobius.gameserver.model.spawns.SpawnTemplate;
+import org.l2jmobius.gameserver.network.NpcStringId;
+import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
+import org.l2jmobius.gameserver.util.Broadcast;
+
+/**
+ * @author Index
+ */
+public class BattleWithKeber extends LongTimeEvent
+{
+ // NPCs
+ private static final int BONNIE = 34216;
+ private static final int KEBER_SEAL_STONE = 18551;
+ // Locations from Bonnie teleport
+ private static final Location PLAINS_OF_GLORY_TELEPORT = new Location(133994, 7136, -4352);
+ private static final Location WAR_TORN_PLAINS_TELEPORT = new Location(161658, 21299, -3672);
+ private static final Location SILENT_VALLEY_TELEPORT = new Location(181645, 52823, -6112);
+ // Spawn locations for monsters
+ private static final Location PLAINS_OF_GLORY_BOSS = new Location(132573, 7865, -4300);
+ private static final Location WAR_TORN_PLAINS_BOSS = new Location(161205, 21680, -3680);
+ private static final Location SILENT_VALLEY_BOSS = new Location(180640, 52824, -6096);
+ // Monsters
+ private static final int KEBER_LOW = 18537; // 63
+ private static final int KEBER_MIDDLE = 18552; // 69
+ private static final int KEBER_HIGH = 18553; // 75
+ private static final int KISHAN = 18538; // 63
+ private static final int NOMA = 18542; // 69
+ private static final int SPALL = 18546; // 75
+ private static final Set BOSSES = new HashSet<>();
+ static
+ {
+ BOSSES.add(KEBER_LOW);
+ BOSSES.add(KEBER_MIDDLE);
+ BOSSES.add(KEBER_HIGH);
+ BOSSES.add(KISHAN);
+ BOSSES.add(NOMA);
+ BOSSES.add(SPALL);
+ }
+ private static final List NORMAL_MINIONS = new ArrayList<>();
+ static
+ {
+ NORMAL_MINIONS.add(18539);
+ NORMAL_MINIONS.add(18543);
+ NORMAL_MINIONS.add(18547);
+ }
+ private static final List ELITE_MINIONS = new ArrayList<>();
+ static
+ {
+ ELITE_MINIONS.add(18540);
+ ELITE_MINIONS.add(18544);
+ ELITE_MINIONS.add(18548);
+ }
+ private static final List BRAINWASHED_MINIONS = new ArrayList<>();
+ static
+ {
+ BRAINWASHED_MINIONS.add(18541);
+ BRAINWASHED_MINIONS.add(18545);
+ BRAINWASHED_MINIONS.add(18549);
+ }
+ // Drop
+ private static final Set KEBER_LOW_DROP = new HashSet<>();
+ static
+ {
+ KEBER_LOW_DROP.add(new ItemChanceHolder(57, 100, 525000)); // Adena x525000
+ KEBER_LOW_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x2
+ KEBER_LOW_DROP.add(new ItemChanceHolder(94481, 100, 150)); // Clan XP x150
+ }
+ private static final Set KEBER_MIDDLE_DROP = new HashSet<>();
+ static
+ {
+ KEBER_MIDDLE_DROP.add(new ItemChanceHolder(57, 100, 725000)); // Adena 725000
+ KEBER_MIDDLE_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x2
+ KEBER_MIDDLE_DROP.add(new ItemChanceHolder(94481, 100, 150)); // Clan XP x150
+ }
+ private static final Set KEBER_HIGH_DROP = new HashSet<>();
+ static
+ {
+ KEBER_HIGH_DROP.add(new ItemChanceHolder(57, 100, 925000)); // Adena x925000
+ KEBER_HIGH_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x2
+ KEBER_HIGH_DROP.add(new ItemChanceHolder(94481, 100, 150)); // Clan XP x150
+ }
+ private static final Set KISHAN_DROP = new HashSet<>();
+ static
+ {
+ KISHAN_DROP.add(new ItemChanceHolder(57, 100, 45000)); // Adena x45000
+ KISHAN_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x1
+ KISHAN_DROP.add(new ItemChanceHolder(94481, 100, 50)); // Clan XP x50
+ }
+ private static final Set NOMA_DROP = new HashSet<>();
+ static
+ {
+ NOMA_DROP.add(new ItemChanceHolder(57, 100, 55000)); // Adena x55000
+ NOMA_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x1
+ NOMA_DROP.add(new ItemChanceHolder(94481, 100, 50)); // Clan XP x50
+ }
+ private static final Set SPALL_DROP = new HashSet<>();
+ static
+ {
+ SPALL_DROP.add(new ItemChanceHolder(57, 100, 65000)); // Adena x55000
+ SPALL_DROP.add(new ItemChanceHolder(91767, 100, 1)); // Enchant Kit: Talisman of Aden x1
+ SPALL_DROP.add(new ItemChanceHolder(94481, 100, 50)); // Clan XP x50
+ }
+ private static final Set MINION_DROP = new HashSet<>();
+ static
+ {
+ MINION_DROP.add(new ItemChanceHolder(91767, 10, 1)); // Enchant Kit: Talisman of Aden x1
+ }
+ private static final Map> NPC_DROP = new HashMap<>();
+ static
+ {
+ NPC_DROP.put(KEBER_LOW, KEBER_LOW_DROP);
+ NPC_DROP.put(KEBER_MIDDLE, KEBER_MIDDLE_DROP);
+ NPC_DROP.put(KEBER_HIGH, KEBER_HIGH_DROP);
+ NPC_DROP.put(KISHAN, KISHAN_DROP);
+ NPC_DROP.put(NOMA, NOMA_DROP);
+ NPC_DROP.put(SPALL, SPALL_DROP);
+ }
+ // Misc
+ private static final int EVENT_MESSAGE_START = -1;
+ private static final int EVENT_MESSAGE_KILL = -2;
+ private static final int EVENT_MESSAGE_TO_KILLER = -3;
+ private static final int EVENT_MESSAGE_WEAK = -4;
+ private static final int ELITE_MONSTER_COUNT = 200;
+ private static final int BRAINWASHED_MONSTER_COUNT = 100;
+ private static final int PLAINS_OF_GLORY_TELEPORT_COST = 2000;
+ private static final int WAR_TORN_PLAINS_TELEPORT_COST = 2500;
+ private static final int SILENT_VALLEY_TELEPORT_COST = 3000;
+ private static final Map BROADCAST_MESSAGES = new HashMap<>();
+ static
+ {
+ BROADCAST_MESSAGES.put(KEBER_LOW, NpcStringId.AHEM_YOU_DARE_TO_BOTHER_KEBER_YOU_WILL_SEE_NO_MERCY);
+ BROADCAST_MESSAGES.put(KEBER_MIDDLE, NpcStringId.AHEM_YOU_DARE_TO_BOTHER_KEBER_YOU_WILL_SEE_NO_MERCY);
+ BROADCAST_MESSAGES.put(KEBER_HIGH, NpcStringId.AHEM_YOU_DARE_TO_BOTHER_KEBER_YOU_WILL_SEE_NO_MERCY);
+ BROADCAST_MESSAGES.put(KISHAN, NpcStringId.KISHAN_MY_SERVANT_ATTACK);
+ BROADCAST_MESSAGES.put(NOMA, NpcStringId.NOMA_MY_SERVANT_ATTACK);
+ BROADCAST_MESSAGES.put(SPALL, NpcStringId.SPALL_MY_SERVANT_ATTACK);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_START, NpcStringId.MAKE_THE_SACRED_BLOOD_SACRIFICE_TO_KEBER_ATTACK);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_KILL, NpcStringId.AH_YOU_ARE_INDEED_STRONG_S1_I_HAVE_TO_RETREAT_THIS_TIME);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_TO_KILLER, NpcStringId.YOU_WILL_NOT_BE_FORGIVEN_I_WILL_BE_BACK_AND_YOU_LL_REGRET_IT);
+ BROADCAST_MESSAGES.put(EVENT_MESSAGE_WEAK, NpcStringId.LOOKS_LIKE_YOU_RE_WAY_TOO_WEAK_TO_BEAT_ME);
+ }
+ private static final AtomicIntegerArray MINION_KILL_COUNTER = new AtomicIntegerArray(3);
+ private static final AtomicReference SPAWN_TEMPLATE = new AtomicReference<>();
+ private static final AtomicIntegerArray MINION_MAX_COUNT = new AtomicIntegerArray(3);
+
+ private BattleWithKeber()
+ {
+ if (isEventPeriod())
+ {
+ addFirstTalkId(BONNIE);
+ addTalkId(BONNIE);
+ addKillId(KEBER_LOW, KEBER_MIDDLE, KEBER_HIGH, KISHAN, NOMA, SPALL);
+ addKillId(NORMAL_MINIONS);
+ addKillId(ELITE_MINIONS);
+ addKillId(BRAINWASHED_MINIONS);
+ addSpawnId(KEBER_LOW, KEBER_MIDDLE, KEBER_HIGH, KISHAN, NOMA, SPALL);
+ addSpawnId(NORMAL_MINIONS);
+ addSpawnId(ELITE_MINIONS);
+ startQuestTimer("KEBER_EVENT_START", getMsTimeForEventStage(1), null, null);
+ SPAWN_TEMPLATE.set(SpawnData.getInstance().getSpawns().stream().filter(t -> t.getName() != null).filter(t -> t.getName().contains("KEBER_MINIONS")).findAny().orElse(null));
+ if (SPAWN_TEMPLATE.get() != null)
+ {
+ MINION_MAX_COUNT.set(0, SPAWN_TEMPLATE.get().getGroups().stream().filter(g -> ((g.getName() != null) && g.getName().equalsIgnoreCase("KISHAN"))).findFirst().get().getSpawns().stream().findFirst().get().getCount());
+ MINION_MAX_COUNT.set(1, SPAWN_TEMPLATE.get().getGroups().stream().filter(g -> ((g.getName() != null) && g.getName().equalsIgnoreCase("NOMA"))).findFirst().get().getSpawns().stream().findFirst().get().getCount());
+ MINION_MAX_COUNT.set(2, SPAWN_TEMPLATE.get().getGroups().stream().filter(g -> ((g.getName() != null) && g.getName().equalsIgnoreCase("SPALL"))).findFirst().get().getSpawns().stream().findFirst().get().getCount());
+ }
+ }
+ }
+
+ @Override
+ public String onAdvEvent(String event, Npc npc, Player player)
+ {
+ switch (event)
+ {
+ case "34216-02.html":
+ {
+ String html = getHtm(player, "34216-02.html");
+ html = html.replace("%n1%", String.valueOf(PLAINS_OF_GLORY_TELEPORT_COST));
+ html = html.replace("%n2%", String.valueOf(WAR_TORN_PLAINS_TELEPORT_COST));
+ html = html.replace("%n3%", String.valueOf(SILENT_VALLEY_TELEPORT_COST));
+ return html;
+ }
+ case "TELEPORT_01":
+ case "TELEPORT_02":
+ case "TELEPORT_03":
+ {
+ final byte requestLocation = Byte.parseByte(event.replace("TELEPORT_0", ""));
+ if (player.getAdena() < (requestLocation == 1 ? PLAINS_OF_GLORY_TELEPORT_COST : requestLocation == 2 ? WAR_TORN_PLAINS_TELEPORT_COST : SILENT_VALLEY_TELEPORT_COST))
+ {
+ return "34216-04.html";
+ }
+ player.teleToLocation((requestLocation == 1 ? PLAINS_OF_GLORY_TELEPORT : requestLocation == 2 ? WAR_TORN_PLAINS_TELEPORT : SILENT_VALLEY_TELEPORT));
+ return "34216-03.html";
+ }
+ case "KEBER_EVENT_START":
+ {
+ for (Npc wo : World.getInstance().getVisibleObjects(player, Npc.class))
+ {
+ if (wo.getId() == KEBER_SEAL_STONE)
+ {
+ wo.setDisplayEffect(1);
+ Broadcast.toKnownPlayers((wo), new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_START), ExShowScreenMessage.TOP_CENTER, 5000));
+ }
+ }
+ MINION_KILL_COUNTER.set(0, 0);
+ MINION_KILL_COUNTER.set(1, 0);
+ MINION_KILL_COUNTER.set(2, 0);
+ SPAWN_TEMPLATE.get().getGroups().forEach(SpawnGroup::spawnAll);
+ cancelQuestTimer("KEBER_EVENT_START", null, null);
+ startQuestTimer("KEBER_EVENT_BOSS_STAGE", getMsTimeForEventStage(2), null, null);
+ break;
+ }
+ case "KEBER_EVENT_BOSS_STAGE":
+ {
+ changeNpcSpawn(3, false, false);
+ for (int fieldType = 0; fieldType < 3; fieldType++)
+ {
+ final int summonedBossId = (getRandomBoolean() ? (fieldType == 0 ? KEBER_LOW : fieldType == 1 ? KEBER_MIDDLE : KEBER_HIGH) : (fieldType == 0 ? KISHAN : fieldType == 1 ? NOMA : SPALL));
+ final Location spawnLoc = (fieldType == 0 ? PLAINS_OF_GLORY_BOSS : fieldType == 1 ? WAR_TORN_PLAINS_BOSS : SILENT_VALLEY_BOSS);
+ addSpawn(summonedBossId, spawnLoc, false, 5 * 60 * 1000); // 5 minutes
+ }
+ cancelQuestTimer("KEBER_EVENT_BOSS_STAGE", null, null);
+ startQuestTimer("KEBER_EVENT_END", getMsTimeForEventStage(3), null, null);
+ break;
+ }
+ case "KEBER_EVENT_END":
+ {
+ for (Npc wo : World.getInstance().getVisibleObjects(player, Npc.class))
+ {
+ if (wo.getId() == KEBER_SEAL_STONE)
+ {
+ wo.setDisplayEffect(2); // remove effect
+ for (Npc boss : World.getInstance().getVisibleObjects((wo), Npc.class))
+ {
+ if (BOSSES.contains(boss.getId()) && !boss.isAlikeDead())
+ {
+ Broadcast.toKnownPlayers((wo), new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_WEAK), ExShowScreenMessage.TOP_CENTER, 5000));
+ break;
+ }
+ }
+ }
+ }
+ cancelQuestTimer("KEBER_EVENT_END", null, null);
+ startQuestTimer("KEBER_EVENT_START", getMsTimeForEventStage(1), null, null);
+ changeNpcSpawn(3, true, true);
+ break;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String onFirstTalk(Npc npc, Player player)
+ {
+ return "34216-01.html";
+ }
+
+ @Override
+ public String onSpawn(Npc npc)
+ {
+ final int type = getFieldType(npc.getId());
+ final boolean eventIsPending = (getQuestTimer("KEBER_EVENT_START", null, null) != null) && getQuestTimer("KEBER_EVENT_START", null, null).isActive();
+ final boolean eventOnBossStage = (getQuestTimer("KEBER_EVENT_END", null, null) != null) && getQuestTimer("KEBER_EVENT_END", null, null).isActive();
+ if ((type != -1) && (npc.getId() == NORMAL_MINIONS.get(type)))
+ {
+ if (eventIsPending || eventOnBossStage)
+ {
+ npc.getSpawn().stopRespawn();
+ npc.deleteMe();
+ return super.onSpawn(npc);
+ }
+
+ final int eliteMonsterId = ELITE_MINIONS.get(type);
+ final int brainWashedMonsterId = BRAINWASHED_MINIONS.get(type);
+ final int nearbyMonstersCount = World.getInstance().getVisibleObjects(npc, Npc.class).stream().filter(nearby -> ((nearby.getId() == NORMAL_MINIONS.get(type)) || (nearby.getId() == eliteMonsterId) || (nearby.getId() == brainWashedMonsterId))).toList().size();
+ final int maxSpawnMonsters = MINION_MAX_COUNT.length() == 0 ? 0 : MINION_MAX_COUNT.get(type);
+ if (nearbyMonstersCount >= maxSpawnMonsters)
+ {
+ npc.deleteMe();
+ return super.onSpawn(npc);
+ }
+ final int killedCount = MINION_KILL_COUNTER.get(type);
+ if (killedCount >= (ELITE_MONSTER_COUNT + BRAINWASHED_MONSTER_COUNT))
+ {
+ addSpawn(brainWashedMonsterId, npc.getLocation());
+ npc.deleteMe();
+ }
+ else if (killedCount >= ELITE_MONSTER_COUNT)
+ {
+ addSpawn(eliteMonsterId, npc.getLocation());
+ npc.deleteMe();
+ }
+ }
+ else if (BOSSES.contains(npc.getId()))
+ {
+ // Broadcast to nearby players string which says "monster respawn"
+ Broadcast.toKnownPlayers(npc, new ExShowScreenMessage(BROADCAST_MESSAGES.get(npc.getId()), ExShowScreenMessage.TOP_CENTER, 5000));
+ World.getInstance().getVisibleObjects(npc, Player.class).stream().findAny().ifPresent(player -> addAttackPlayerDesire(npc, player));
+ }
+ return super.onSpawn(npc);
+ }
+
+ @Override
+ public String onKill(Npc npc, Player killer, boolean isSummon)
+ {
+ if (NORMAL_MINIONS.contains(npc.getId()) || ELITE_MINIONS.contains(npc.getId()))
+ {
+ final int type = getFieldType(npc.getId());
+ int count = MINION_KILL_COUNTER.get(type);
+ if ((count >= ELITE_MONSTER_COUNT) && ELITE_MINIONS.contains(npc.getId()))
+ {
+ MINION_KILL_COUNTER.addAndGet(type, 1);
+ }
+ else if (count < ELITE_MONSTER_COUNT)
+ {
+ MINION_KILL_COUNTER.addAndGet(type, 1);
+ }
+ }
+ else
+ {
+ final Set monsterDrop = ((npc.getTemplate().getLevel() > (killer.getLevel() - 15)) && (npc.getTemplate().getLevel() < (killer.getLevel() + 15))) ? NPC_DROP.getOrDefault(npc.getId(), MINION_DROP) : new HashSet<>();
+ for (ItemChanceHolder drop : monsterDrop)
+ {
+ if (getRandom(100) < drop.getChance())
+ {
+ if ((drop.getId() == 94481) && (killer.getClan() != null)) // Avoid to get clan points as item.
+ {
+ killer.getClan().addExp(killer.getObjectId(), (int) drop.getCount());
+ }
+ else
+ {
+ killer.addItem(_eventName, drop.getId(), drop.getCount(), null, true);
+ }
+ }
+ }
+ if (BOSSES.contains(npc.getId()))
+ {
+ changeNpcSpawn(getFieldType(npc.getId()), true, false);
+ Broadcast.toKnownPlayers(killer, new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_KILL), ExShowScreenMessage.TOP_CENTER, 10000, killer.getName()));
+ killer.sendPacket(new ExShowScreenMessage(BROADCAST_MESSAGES.get(EVENT_MESSAGE_TO_KILLER), ExShowScreenMessage.TOP_CENTER, 5000));
+ for (Npc crystal : World.getInstance().getVisibleObjects(npc, Npc.class))
+ {
+ if (crystal.getId() == KEBER_SEAL_STONE)
+ {
+ crystal.setDisplayEffect(2);
+ break;
+ }
+ }
+ }
+ }
+ return super.onKill(npc, killer, isSummon);
+ }
+
+ private long getMsTimeForEventStage(int type)
+ {
+ final Calendar returnTime = Calendar.getInstance();
+ final long currentTime = System.currentTimeMillis();
+ returnTime.set(Calendar.MILLISECOND, 0);
+ returnTime.set(Calendar.SECOND, 0);
+ if (type == 1)
+ {
+ returnTime.set(Calendar.MINUTE, 0);
+ returnTime.add(Calendar.HOUR_OF_DAY, 1);
+ }
+ else if (type == 2)
+ {
+ returnTime.add(Calendar.MINUTE, 10);
+ }
+ else if (type == 3)
+ {
+ returnTime.add(Calendar.MINUTE, 5);
+ }
+ if (returnTime.getTimeInMillis() < currentTime)
+ {
+ returnTime.add(Calendar.DAY_OF_YEAR, 1);
+ }
+ return returnTime.getTimeInMillis() - currentTime;
+ }
+
+ /**
+ * Because value is set and we know all ids, it can be used to get fast access to any field monster.
+ * @param npcId
+ * @return 0 - Plains, 1 - War-Torn, 2 - Silent Valley
+ */
+ private int getFieldType(int npcId)
+ {
+ if ((npcId == KEBER_LOW) || (npcId == KISHAN) || (npcId == NORMAL_MINIONS.get(0)) || (npcId == ELITE_MINIONS.get(0)) || (npcId == BRAINWASHED_MINIONS.get(0)))
+ {
+ return 0;
+ }
+ else if ((npcId == KEBER_MIDDLE) || (npcId == NOMA) || (npcId == NORMAL_MINIONS.get(1)) || (npcId == ELITE_MINIONS.get(1)) || (npcId == BRAINWASHED_MINIONS.get(1)))
+ {
+ return 1;
+ }
+ else if ((npcId == KEBER_HIGH) || (npcId == SPALL) || (npcId == NORMAL_MINIONS.get(2)) || (npcId == ELITE_MINIONS.get(2)) || (npcId == BRAINWASHED_MINIONS.get(2)))
+ {
+ return 2;
+ }
+ return -1;
+ }
+
+ private void changeNpcSpawn(int type, boolean delete, boolean removeAll)
+ {
+ if (removeAll)
+ {
+ SPAWN_TEMPLATE.get().getGroups().forEach(SpawnGroup::despawnAll);
+ }
+
+ for (WorldObject wo : World.getInstance().getVisibleObjects())
+ {
+ if (!wo.isMonster())
+ {
+ continue;
+ }
+
+ if (((type == 0) || (type == 3)) //
+ && ((!removeAll && (NORMAL_MINIONS.get(0) == wo.getId())) //
+ || (ELITE_MINIONS.get(0) == wo.getId()) //
+ || (BRAINWASHED_MINIONS.get(0) == wo.getId()) //
+ || (removeAll && ((KISHAN == wo.getId()) || (KEBER_LOW == wo.getId())))))
+ {
+ removeSpawn(wo, delete);
+ }
+ if (((type == 1) || (type == 3)) //
+ && ((!removeAll && (NORMAL_MINIONS.get(1) == wo.getId())) //
+ || (ELITE_MINIONS.get(1) == wo.getId()) //
+ || (BRAINWASHED_MINIONS.get(1) == wo.getId()) //
+ || (removeAll && ((NOMA == wo.getId()) || (KEBER_MIDDLE == wo.getId())))))
+ {
+ removeSpawn(wo, delete);
+ }
+ if (((type == 2) || (type == 3)) //
+ && ((!removeAll && (NORMAL_MINIONS.get(2) == wo.getId())) //
+ || (ELITE_MINIONS.get(2) == wo.getId()) //
+ || (BRAINWASHED_MINIONS.get(2) == wo.getId()) //
+ || (removeAll && ((SPALL == wo.getId()) || (KEBER_HIGH == wo.getId())))))
+ {
+ removeSpawn(wo, delete);
+ }
+ }
+ }
+
+ private void removeSpawn(WorldObject wo, boolean delete)
+ {
+ final Npc npc = ((Npc) wo);
+ npc.getSpawn().stopRespawn();
+ if (delete && (!BOSSES.contains(npc.getTemplate().getId()) || !npc.isAlikeDead()))
+ {
+ npc.deleteMe();
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ new BattleWithKeber();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/config.xml b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/config.xml
new file mode 100644
index 0000000000..9de724646b
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/scripts/events/BattleWithKeber/config.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/spawns/Event/BattleWithKeber.xml b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/spawns/Event/BattleWithKeber.xml
new file mode 100644
index 0000000000..2da5f42b64
--- /dev/null
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/spawns/Event/BattleWithKeber.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/18500-18599.xml b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/18500-18599.xml
index b4f5568ab1..16a7913b83 100644
--- a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/18500-18599.xml
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/18500-18599.xml
@@ -1137,6 +1137,10 @@
+
+
+
+
@@ -1164,6 +1168,10 @@
+
+
+
+
@@ -1186,6 +1194,9 @@
+
+
+
@@ -1207,6 +1218,10 @@
+
+
+
+
@@ -1234,6 +1249,10 @@
+
+
+
+
@@ -1260,6 +1279,10 @@
+
+
+
+
@@ -1282,6 +1305,9 @@
+
+
+
@@ -1303,6 +1329,10 @@
+
+
+
+
@@ -1329,6 +1359,10 @@
+
+
+
+
@@ -1355,6 +1389,10 @@
+
+
+
+
@@ -1376,6 +1414,9 @@
+
+
+
@@ -1396,8 +1437,7 @@
-
-
+
ETC
MALE
@@ -1411,11 +1451,14 @@
600
-
+
+
+
+
@@ -1437,6 +1480,10 @@
+
+
+
+
@@ -1458,6 +1505,10 @@
+
+
+
+
diff --git a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/34200-34299.xml b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/34200-34299.xml
index 42114c53d4..86ebe61c7a 100644
--- a/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/34200-34299.xml
+++ b/L2J_Mobius_Essence_6.2_Vanguard/dist/game/data/stats/npcs/34200-34299.xml
@@ -431,13 +431,13 @@
-
+
-
+