From 24bc5b65946c4db58f394fffd7aea91c1eabe938 Mon Sep 17 00:00:00 2001 From: MobiusDev <8391001+MobiusDevelopment@users.noreply.github.com> Date: Sun, 10 Sep 2017 12:29:08 +0000 Subject: [PATCH] Lindvior AI. Contributed by gigilo1968. --- .../db_installer/sql/game/grandboss_data.sql | 5 +- .../dist/game/config/GrandBoss.ini | 21 +- .../dist/game/data/Routes.xml | 4 + .../AltarOfSacrifice/AltarOfSacrifice.java | 2 +- .../scripts/ai/bosses/Lindvior/19477-01.html | 3 + .../scripts/ai/bosses/Lindvior/19477.html | 3 + .../bosses/Lindvior/KatoSicanus/33881-1.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-2.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-3.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-4.html | 3 + .../bosses/Lindvior/KatoSicanus/33881-5.html | 3 + .../ai/bosses/Lindvior/KatoSicanus/33881.html | 6 + .../Lindvior/KatoSicanus/KatoSicanus.java | 129 +++ .../scripts/ai/bosses/Lindvior/Lindvior.java | 976 ++++++++++++++++++ .../ai/bosses/Lindvior/LindviorBoss.java | 175 ++++ .../ai/bosses/Lindvior/LionelHunter.java | 67 ++ .../scripts/ai/bosses/Lindvior/Vortex.java | 176 ++++ .../dist/game/data/stats/npcs/08500-08599.xml | 2 +- .../dist/game/data/stats/npcs/19400-19499.xml | 81 +- .../dist/game/data/stats/npcs/25800-25899.xml | 54 +- .../dist/game/data/stats/npcs/29200-29299.xml | 24 +- .../game/data/stats/skills/15600-15699.xml | 25 +- .../dist/game/data/zones/no_summon_friend.xml | 14 + .../java/com/l2jmobius/Config.java | 12 + L2J_Mobius_1.0_Ertheia/readme.txt | 1 - .../db_installer/sql/game/grandboss_data.sql | 5 +- .../dist/game/config/GrandBoss.ini | 21 +- .../dist/game/data/Routes.xml | 4 + .../AltarOfSacrifice/AltarOfSacrifice.java | 2 +- .../scripts/ai/bosses/Lindvior/19477-01.html | 3 + .../scripts/ai/bosses/Lindvior/19477.html | 3 + .../bosses/Lindvior/KatoSicanus/33881-1.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-2.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-3.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-4.html | 3 + .../bosses/Lindvior/KatoSicanus/33881-5.html | 3 + .../ai/bosses/Lindvior/KatoSicanus/33881.html | 6 + .../Lindvior/KatoSicanus/KatoSicanus.java | 129 +++ .../scripts/ai/bosses/Lindvior/Lindvior.java | 976 ++++++++++++++++++ .../ai/bosses/Lindvior/LindviorBoss.java | 175 ++++ .../ai/bosses/Lindvior/LionelHunter.java | 67 ++ .../scripts/ai/bosses/Lindvior/Vortex.java | 176 ++++ .../dist/game/data/stats/npcs/08500-08599.xml | 2 +- .../dist/game/data/stats/npcs/19400-19499.xml | 81 +- .../dist/game/data/stats/npcs/25800-25899.xml | 54 +- .../dist/game/data/stats/npcs/29200-29299.xml | 184 ++-- .../game/data/stats/skills/15600-15699.xml | 25 +- .../dist/game/data/zones/no_summon_friend.xml | 14 + .../java/com/l2jmobius/Config.java | 12 + L2J_Mobius_2.5_Underground/readme.txt | 1 - .../db_installer/sql/game/grandboss_data.sql | 5 +- .../dist/game/config/GrandBoss.ini | 21 +- .../dist/game/data/Routes.xml | 4 + .../AltarOfSacrifice/AltarOfSacrifice.java | 2 +- .../scripts/ai/bosses/Lindvior/19477-01.html | 3 + .../scripts/ai/bosses/Lindvior/19477.html | 3 + .../bosses/Lindvior/KatoSicanus/33881-1.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-2.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-3.html | 4 + .../bosses/Lindvior/KatoSicanus/33881-4.html | 3 + .../bosses/Lindvior/KatoSicanus/33881-5.html | 3 + .../ai/bosses/Lindvior/KatoSicanus/33881.html | 6 + .../Lindvior/KatoSicanus/KatoSicanus.java | 129 +++ .../scripts/ai/bosses/Lindvior/Lindvior.java | 976 ++++++++++++++++++ .../ai/bosses/Lindvior/LindviorBoss.java | 175 ++++ .../ai/bosses/Lindvior/LionelHunter.java | 67 ++ .../scripts/ai/bosses/Lindvior/Vortex.java | 176 ++++ .../dist/game/data/stats/npcs/08500-08599.xml | 2 +- .../dist/game/data/stats/npcs/19400-19499.xml | 81 +- .../dist/game/data/stats/npcs/25800-25899.xml | 54 +- .../dist/game/data/stats/npcs/29200-29299.xml | 184 ++-- .../game/data/stats/skills/15600-15699.xml | 25 +- .../dist/game/data/zones/no_summon_friend.xml | 14 + .../java/com/l2jmobius/Config.java | 12 + L2J_Mobius_3.0_Helios/readme.txt | 1 - 75 files changed, 5372 insertions(+), 342 deletions(-) create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java diff --git a/L2J_Mobius_1.0_Ertheia/dist/db_installer/sql/game/grandboss_data.sql b/L2J_Mobius_1.0_Ertheia/dist/db_installer/sql/game/grandboss_data.sql index b653bdee9c..df0cbd30aa 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/db_installer/sql/game/grandboss_data.sql +++ b/L2J_Mobius_1.0_Ertheia/dist/db_installer/sql/game/grandboss_data.sql @@ -17,8 +17,9 @@ INSERT IGNORE INTO `grandboss_data` (`boss_id`,`loc_x`,`loc_y`,`loc_z`,`heading` (29006, 17726, 108915, -6480, 0, 622493.58388, 3793.536), -- Core (29014, 55024, 17368, -5412, 10126, 622493.58388, 3793.536), -- Orfen (29020, 116033, 17447, 10107, -25348, 4068372, 39960), -- Baium -(29028, -105200, -253104, -15264, 0, 62041918, 2248572), -- Valakas (29068, 185708, 114298, -8221,32768, 62802301, 1998000), -- Antharas +(29028, -105200, -253104, -15264, 0, 62041918, 2248572), -- Valakas +(29240, 0, 0, 0, 0, 288282589, 47100), -- Lindvior (29118, 0, 0, 0, 0, 4109288, 1220547), -- Beleth (25286, 185080, -12613, -5499, 16550, 556345880, 86847), -- Anakim -(25283, 185062, -9605, -5499, 15640, 486021997, 79600); -- Lilith \ No newline at end of file +(25283, 185062, -9605, -5499, 15640, 486021997, 79600); -- Lilith diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/config/GrandBoss.ini b/L2J_Mobius_1.0_Ertheia/dist/game/config/GrandBoss.ini index 21b6037556..3689173278 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/config/GrandBoss.ini +++ b/L2J_Mobius_1.0_Ertheia/dist/game/config/GrandBoss.ini @@ -144,4 +144,23 @@ LilithMaxPlayers = 120 LilithMinPlayerLvl = 85 # Maximum players Level for enter to Lilith. Retail: 89 -LilithMaxPlayerLvl = 89 \ No newline at end of file +LilithMaxPlayerLvl = 89 + +# --------------------------------------------------------------------------- +# Lindvior +# --------------------------------------------------------------------------- + +# Interval time of Lindvior. Value is hour. Range 1-480. Retail: 264 +IntervalOfLindviorSpawn = 264 + +# Random interval. Range 1-192. Retail: 72 +RandomOfLindviorSpawn = 72 + +# Minimal count of players for enter to Lindvior. Retail: 49 +LindviorMinPlayers = 49 + +# Maximum count of players for enter to Lindvior. Retail: 112 +LindviorMaxPlayers = 112 + +# Minimum players Level for enter to Lindvior. Retail: 99 +LindviorMinPlayerLvl = 99 \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml index 5cbbf5261f..dc0e5372c2 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml @@ -2352,4 +2352,8 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java index 790799b0ad..b1a37e194f 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java @@ -75,7 +75,7 @@ public class AltarOfSacrifice extends AbstractNpcAI @Override public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon) { - if (creature.isPlayer() && _jenas_guard.isScriptValue(0)) + if ((creature != null) && creature.isPlayer() && _jenas_guard.isScriptValue(0)) { startQuestTimer("msg_text", 3000, npc, null); _jenas_guard.setScriptValue(1); diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html new file mode 100644 index 0000000000..5f9fc4431e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html @@ -0,0 +1,3 @@ +Generator:
+The generator is now supplying power to the sealed structure. + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477.html new file mode 100644 index 0000000000..540ff6ac54 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/19477.html @@ -0,0 +1,3 @@ +Generator:

+ + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html new file mode 100644 index 0000000000..ba01eab970 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+On the Lindvior there is an attack!
+At this time it's impossible to enter the altar. + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html new file mode 100644 index 0000000000..e3eac44ec7 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+Lindvior? You're too late, friend.
+A group of warriors drove him off not long ago. + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html new file mode 100644 index 0000000000..40de9b961e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+You are overcome by a voice, a voice so powerful you are helpless as it speaks:
+(The players who belong to an association can only enter through the Association Leader.) + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html new file mode 100644 index 0000000000..9af5ff8c7a --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html @@ -0,0 +1,3 @@ +Rune Castle Patrol Kato:
+(A command channel needs at least minimu: %min% and maximum: %max% members to challenge Lindvior.) + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html new file mode 100644 index 0000000000..309c938f02 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html @@ -0,0 +1,3 @@ +Rune Castle Patrol Kato:
+(A command channel members level must be minimum: %minlvl% Lvl or higher to challenge Lindvior.) + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html new file mode 100644 index 0000000000..bddff0b348 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html @@ -0,0 +1,6 @@ +Rune Castle Patrol Kato:
+Dire times dictated that I come myself from Rune Castle to help those in need here.
+What do you need?
+ + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java new file mode 100644 index 0000000000..3b54f9dfa8 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java @@ -0,0 +1,129 @@ +/* + * 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 ai.bosses.Lindvior.KatoSicanus; + +import java.util.List; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.instancemanager.GrandBossManager; +import com.l2jmobius.gameserver.model.L2Party; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; + +import ai.AbstractNpcAI; + +/** + * Kato Sicanus Teleporter AI + * @author Gigi + * @date 2017-07-13 - [22:17:16] + */ +public class KatoSicanus extends AbstractNpcAI +{ + // NPCs + private static final int KATO_SICANUS = 33881; + private static final int LINDVIOR_RAID = 29240; + private static final int INVISIBLE = 8572; + // Location + private static final Location LINDVIOR_LOCATION = new Location(46929, -28807, -1400); + + public KatoSicanus() + { + addFirstTalkId(KATO_SICANUS); + addTalkId(KATO_SICANUS); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.equals("teleport")) + { + final int status = GrandBossManager.getInstance().getBossStatus(LINDVIOR_RAID); + if (player.isGM()) + { + player.teleToLocation(LINDVIOR_LOCATION, true); + addSpawn(INVISIBLE, 46707, -28586, -1400, 0, false, 60000, false); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, 1); + } + else + { + if (status == 2) + { + return "33881-1.html"; + } + if (status == 3) + { + return "33881-2.html"; + } + if (!player.isInParty()) + { + return "33881-3.html"; + } + final L2Party party = player.getParty(); + final boolean isInCC = party.isInCommandChannel(); + final List members = (isInCC) ? party.getCommandChannel().getMembers() : party.getMembers(); + final boolean isPartyLeader = (isInCC) ? party.getCommandChannel().isLeader(player) : party.isLeader(player); + if (!isPartyLeader) + { + return "33881-3.html"; + } + if ((members.size() < Config.LINDVIOR_MIN_PLAYERS) || (members.size() > Config.LINDVIOR_MAX_PLAYERS)) + { + final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId()); + packet.setHtml(getHtm(player.getHtmlPrefix(), "33881-4.html")); + packet.replace("%min%", Integer.toString(Config.LINDVIOR_MIN_PLAYERS)); + packet.replace("%max%", Integer.toString(Config.LINDVIOR_MAX_PLAYERS)); + player.sendPacket(packet); + return null; + } + for (L2PcInstance member : members) + { + if (member.getLevel() < Config.LINDVIOR_MIN_PLAYER_LVL) + { + final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId()); + packet.setHtml(getHtm(player.getHtmlPrefix(), "33881-5.html")); + packet.replace("%minlvl%", Integer.toString(Config.LINDVIOR_MIN_PLAYER_LVL)); + player.sendPacket(packet); + return null; + } + } + for (L2PcInstance member : members) + { + if (member.isInsideRadius(npc, 1500, true, false)) + { + member.teleToLocation(LINDVIOR_LOCATION, true); + addSpawn(INVISIBLE, 46707, -28586, -1400, 0, false, 0, false); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, 1); + } + } + } + } + return null; + } + + @Override + public String onFirstTalk(L2Npc npc, L2PcInstance player) + { + return "33881.html"; + } + + public static void main(String[] args) + { + new KatoSicanus(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java new file mode 100644 index 0000000000..d6247a96c6 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java @@ -0,0 +1,976 @@ +/* + * 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 ai.bosses.Lindvior; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledFuture; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.enums.Movie; +import com.l2jmobius.gameserver.instancemanager.GrandBossManager; +import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance; +import com.l2jmobius.gameserver.model.actor.instance.L2GuardInstance; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.events.EventType; +import com.l2jmobius.gameserver.model.events.ListenerRegisterType; +import com.l2jmobius.gameserver.model.events.annotations.Id; +import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent; +import com.l2jmobius.gameserver.model.events.annotations.RegisterType; +import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureDamageReceived; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.Skill; +import com.l2jmobius.gameserver.model.zone.L2ZoneType; +import com.l2jmobius.gameserver.model.zone.type.L2NoSummonFriendZone; +import com.l2jmobius.gameserver.network.NpcStringId; +import com.l2jmobius.gameserver.network.serverpackets.Earthquake; +import com.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import com.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; +import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; +import com.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; +import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera; + +import ai.AbstractNpcAI; + +/** + * Lindvior Boss + * @author Gigi + * @date 2017-07-11 - [17:42:53] + *

+ * @VIDEO - https://www.youtube.com/watch?v=VknjOjRO9Cw + */ +public class Lindvior extends AbstractNpcAI +{ + // Monsters + private static final int LINDVIOR_FAKE = 19423; + private static final int LINDVIOR_GROUND = 25899; + private static final int LINDVIOR_RAID = 29240; + private static final int LINDVIOR_FLY = 19424; + private static final int NPC_GENERATOR = 19477; + private static final int GENERATOR_GUARD = 19479; + private static final int NPC_ATTACKER_GENERATORS = 25897; + private static final int NPC_ATTACKER_GENERATORS_1 = 25895; + private static final int LYN_DRACO_ATTACKER_GENERATORS = 29241; + private static final int NPC_ATTACKER_SMALL_VORTEX = 25898; + private static final int NPC_ATTACKER_BIG_VORTEX = 19427; + private static final int INVISIBLE = 8572; + private static final int LIONEL_HUNTER = 33886; + private static final int LINDVIOR_CAMERA = 19428; + // Zone + private final static int ZONE_ID = 12107; + static final Location CENTER_LOCATION = new Location(46424, -26200, -1400); + // Skills + private static final SkillHolder SKILL_RECHARGE_POSIBLE = new SkillHolder(15605, 1); + private static final SkillHolder RECHARGE = new SkillHolder(15606, 1); + private static final SkillHolder SKILL_REFLECT = new SkillHolder(15592, 1); + // Item + private static final int LINDVIORS_SCALE = 37495; + // Trigers + private static final int FIRST_STAGE_EVENT_TRIGGER = 21170112; + private static final int SECOND_STAGE_EVENT_TRIGGER = 21170100; + private static final int ALL_GENERATORS_CONNECTED_EFFECT = 21170110; + private static final int RED_ZONE_EFFECT = 21170120; + // Status + private static final int ALIVE = 0; + private static final int FIGHTING = 2; + private static final int DEAD = 3; + // Tasks + protected ScheduledFuture _socialTask; + protected ScheduledFuture _mobsSpawnTask; + protected ScheduledFuture _collapseTask; + protected ScheduledFuture _announceTask; + protected ScheduledFuture _announceProtect; + protected ScheduledFuture _skillCastTask; + protected ScheduledFuture _LynDracoTask; + protected ScheduledFuture _smallVortexesTask; + protected ScheduledFuture _bigVortexesTask; + protected L2NoSummonFriendZone _zoneLair; + protected L2GrandBossInstance _lindvior = null; + protected L2Npc _lindvior2 = null; + protected L2Npc _dummyLindvior; + protected L2Npc _vortex = null; + protected L2Npc _lionel = null; + protected List _guardSpawn = new ArrayList<>(); + protected List _generatorSpawn = new ArrayList<>(); + protected List _monsterSpawn = new ArrayList<>(); + protected List _LinDracoSpawn = new ArrayList<>(); + protected int _activeMask = 0; + protected int _chargedMask = 0; + protected int _status = 0; + + private static final Location[] CONTROL_GENERATOR_SPAWNS = + { + new Location(45288, -30360, -1432, 0), + new Location(48486, -27175, -1432, 0), + new Location(45272, -23976, -1432, 0), + new Location(42088, -27160, -1432, 0) + }; + private static final Location[] SCHEME_GENERATOR_SPAWNS = + { + new Location(48440, -26824, -1438, 0), + new Location(48392, -27448, -1438, 0), + new Location(42136, -27480, -1438, 0), + new Location(42136, -26840, -1438, 0), + new Location(44936, -24024, -1438, 0), + new Location(45592, -24008, -1438, 0), + new Location(45608, -30312, -1438, 0), + new Location(44984, -30360, -1438, 0) + }; + private static final Location[] ATTACKER_GENERATOR_SPAWNS = + { + new Location(44863, -24272, -1413, 33713), + new Location(45675, -24272, -1413, 33713), + new Location(45675, -30057, -1413, 64987), + new Location(44863, -30057, -1413, 64987), + new Location(42350, -27563, -1413, 46871), + new Location(42350, -26809, -1413, 46871), + new Location(48220, -26809, -1413, 16383), + new Location(48220, -27563, -1413, 16383) + }; + private static final Location[] LYN_DRACO_SPAWNS = + { + new Location(45300, -28402, -1400, 48845), + new Location(46379, -27178, -1400, 1154), + new Location(45292, -26043, -1400, 13027), + new Location(44215, -27172, -1400, 33966) + }; + private static final Location[] ATTACKER_SMALL_VORTEX_SPAWNS = new Location[] + { + new Location(46256, -30159, -1430, 57430), + new Location(45155, -29987, -1430, 14860), + new Location(46219, -27704, -1430, 1744), + new Location(46135, -28995, -1430, 43626), + new Location(43973, -28265, -1430, 16516), + new Location(46782, -29065, -1430, 63368), + new Location(47214, -29836, -1430, 46966), + new Location(44754, -29120, -1430, 56118), + new Location(47089, -28198, -1430, 8537), + new Location(44992, -28152, -1430, 11592), + new Location(44737, -24885, -1430, 3146), + new Location(46096, -24976, -1430, 49650), + new Location(46972, -25911, -1430, 62925), + new Location(46977, -27136, -1430, 2150), + new Location(42889, -24767, -1430, 10246), + new Location(47299, -25256, -1430, 1453), + new Location(44204, -25026, -1430, 39225), + new Location(42875, -28035, -1430, 34755), + new Location(41963, -26031, -1430, 18822), + new Location(43171, -25942, -1430, 44279), + new Location(41874, -27174, -1430, 56030), + new Location(44983, -26082, -1430, 7042), + new Location(46145, -26804, -1430, 24394), + new Location(46148, -26019, -1430, 34151), + new Location(45161, -24275, -1430, 39262), + new Location(47288, -24141, -1430, 21644), + new Location(43722, -26174, -1430, 11001), + new Location(44942, -27169, -1430, 39703), + new Location(46105, -24170, -1430, 28224), + new Location(49084, -27206, -1430, 41996), + new Location(48159, -27091, -1430, 62682), + new Location(48094, -28789, -1430, 49189), + new Location(48958, -27844, -1430, 59758), + new Location(43828, -23981, -1430, 10994), + new Location(48165, -25777, -1430, 53084), + new Location(48267, -28086, -1430, 9266), + new Location(43268, -28981, -1430, 23736), + new Location(44155, -29821, -1430, 39281), + new Location(43991, -29275, -1430, 27277), + new Location(44057, -27133, -1430, 64484), + new Location(43257, -26764, -1430, 14161), + new Location(42300, -25194, -1430, 7811), + new Location(42091, -27981, -1430, 30628), + new Location(47854, -24735, -1430, 14438) + }; + // @formatter:off + private static final int[][] GENERATOR_TRIGERS = + { + {21170102, 21170103}, + {21170104, 21170105}, + {21170106, 21170107}, + {21170108, 21170109} + }; + protected final int _chargedValues[] = new int[] {0, 0, 0, 0}; + private static final int[] LINDVIOR_SERVITOR = {25895, 25896, 25897, 29242, 29241, 29243}; + // @formatter:on + private static final NpcStringId[] GUARD_MSG = + { + NpcStringId.ACTIVATE_THE_GENERATOR_HURRY, + NpcStringId.WE_WILL_HOLD_OFF_LINDVIOR_S_MINIONS, + }; + private static final NpcStringId[] GUARD_MSG_1 = + { + NpcStringId.HOLD_ONTO_THE_GENERATOR_TO_ACTIVATE_THE_CHARGE_SKILL, + NpcStringId.THE_GENERATOR_IS_CONNECTED_TO_THE_CANNON, + }; + + public Lindvior() + { + super(); + addAttackId(LINDVIOR_GROUND, LINDVIOR_FLY, LINDVIOR_RAID); + addEnterZoneId(ZONE_ID); + addExitZoneId(ZONE_ID); + addKillId(LINDVIOR_RAID, NPC_GENERATOR); + addSkillSeeId(NPC_GENERATOR); + addSpawnId(NPC_ATTACKER_GENERATORS, NPC_ATTACKER_GENERATORS_1, LYN_DRACO_ATTACKER_GENERATORS, GENERATOR_GUARD, NPC_GENERATOR); + addFirstTalkId(NPC_GENERATOR); + addSeeCreatureId(INVISIBLE); + _zoneLair = ZoneManager.getInstance().getZoneById(ZONE_ID, L2NoSummonFriendZone.class); + // Unlock + final StatsSet info = GrandBossManager.getInstance().getStatsSet(LINDVIOR_RAID); + final long time = info.getLong("respawn_time") - System.currentTimeMillis(); + if (time > 0) + { + startQuestTimer("unlock_lindvior", time, null, null); + } + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + // Anti BUGGERS + if (!_zoneLair.isInsideZone(attacker)) + { + attacker.doDie(null); + _log.warning(getName() + ": Character: " + attacker.getName() + " attacked: " + npc.getName() + " out of the boss zone!"); + } + if (!_zoneLair.isInsideZone(npc)) + { + npc.teleToLocation(CENTER_LOCATION, true); + _log.warning(getName() + ": Character: " + attacker.getName() + " attacked: " + npc.getName() + " wich is out of the boss zone!"); + } + + double percent = ((npc.getCurrentHp() - damage) / npc.getMaxHp()) * 100; + if ((percent <= 80) && (_status == 0)) + { + _zoneLair.broadcastPacket(new OnEventTrigger(RED_ZONE_EFFECT, true)); + _zoneLair.getPlayersInside().stream().forEach(p -> + { + startQuestTimer("stop_red_zone", 10000, _lindvior, p); + p.broadcastPacket(new ExShowScreenMessage(NpcStringId.A_FEARSOME_POWER_EMANATES_FROM_LINDVIOR, ExShowScreenMessage.TOP_CENTER, 2000, true)); + }); + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_FLY, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.8); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true); + addSpawn(LINDVIOR_SERVITOR[0], loc, true); + } + _status = 1; + } + else if ((percent <= 75) && (_status == 1)) + { + _bigVortexesTask = ThreadPoolManager.schedule(() -> spawnServitor(1, 300, _lindvior.getLocation(), NPC_ATTACKER_BIG_VORTEX), 1000); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(LINDVIOR_SERVITOR[1], loc, true); + } + _zoneLair.getPlayersInside().stream().forEach(p -> p.broadcastPacket(new ExShowScreenMessage(NpcStringId.A_GIGANTIC_WHIRLWIND_HAS_APPEARED, ExShowScreenMessage.TOP_CENTER, 2000, true))); + _status = 2; + } + else if ((percent <= 60) && (_status == 2)) + { + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_GROUND, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.6); + spawnServitor(10, 2000, _lindvior.getLocation(), LINDVIOR_SERVITOR); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(LINDVIOR_SERVITOR[2], loc, true); + } + _skillCastTask = ThreadPoolManager.scheduleAtFixedRate(() -> _lindvior.doCast(SKILL_REFLECT.getSkill()), 5000, 80000); + _status = 3; + } + else if ((percent <= 40) && (_status == 3)) + { + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_FLY, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.4); + + if (SpawnTable.getInstance().getSpawns(NPC_ATTACKER_BIG_VORTEX) != null) + { + if ((_vortex != null) && (_vortex.getId() == NPC_ATTACKER_SMALL_VORTEX)) + { + _vortex.getSpawn().stopRespawn(); + _vortex.deleteMe(); + } + } + _status = 4; + } + else if ((percent <= 35) && (_status == 4)) + { + _smallVortexesTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true, 60000); + addSpawn(LINDVIOR_SERVITOR[3], loc, true); + } + + }, 20000, 60000); + _status = 5; + } + else if ((percent <= 20) && (_status == 5)) + { + if (_smallVortexesTask != null) + { + _smallVortexesTask.cancel(true); + _smallVortexesTask = null; + } + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.LINDVIOR_HAS_LANDED, 2, 5000, true)); + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_RAID, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.2); + _bigVortexesTask = ThreadPoolManager.schedule(() -> spawnServitor(1, 300, _lindvior.getLocation(), NPC_ATTACKER_BIG_VORTEX), 1000); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true); + addSpawn(LINDVIOR_SERVITOR[4], loc, true); + addSpawn(LINDVIOR_SERVITOR[3], loc, true); + } + _collapseTask = ThreadPoolManager.schedule(Lindvior.this::Clean, 600000); + _status = 6; + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + protected void Clean() + { + _status = 0; + if (_socialTask != null) + { + _socialTask.cancel(false); + _socialTask = null; + } + if (_announceTask != null) + { + _announceTask.cancel(false); + _announceTask = null; + } + if (_announceProtect != null) + { + _announceProtect.cancel(false); + _announceProtect = null; + } + if (_skillCastTask != null) + { + _skillCastTask.cancel(false); + _skillCastTask = null; + } + if (_LynDracoTask != null) + { + _LynDracoTask.cancel(false); + _LynDracoTask = null; + } + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(false); + _mobsSpawnTask = null; + } + if (_collapseTask != null) + { + _collapseTask.cancel(false); + _collapseTask = null; + } + if (_bigVortexesTask != null) + { + _bigVortexesTask.cancel(false); + _bigVortexesTask = null; + } + if (_smallVortexesTask != null) + { + _smallVortexesTask.cancel(false); + _smallVortexesTask = null; + } + if (_lionel != null) + { + _lionel.deleteMe(); + } + _zoneLair.getCharactersInside().forEach(mob -> + { + if (mob.isNpc()) + { + mob.deleteMe(); + mob.setIsDead(true); + } + }); + } + + private void Fail(boolean clean) + { + if (clean) + { + Clean(); + } + _zoneLair.oustAllPlayers(); + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, false)); + cancelQuestTimers("attack_generator"); + if (GrandBossManager.getInstance().getBossStatus(LINDVIOR_RAID) != 3) + { + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, ALIVE); + } + } + + @Override + public synchronized String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon) + { + if ((skill.getId() == 15606) && (npc.getId() == NPC_GENERATOR)) + { + synchronized (_chargedValues) + { + int index = npc.getScriptValue(); + if (!hasFlag(_chargedMask, 1 << index)) + { + _chargedValues[index] += caster.isGM() ? (30 / 4) + 2 : (1 / 4) + 2; + _chargedValues[index] = Math.min(_chargedValues[index], 120); + + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 3000, player -> + { + player.sendPacket(new ExShowScreenMessage(NpcStringId.S1_HAS_CHARGED_THE_CANNON, ExShowScreenMessage.TOP_CENTER, 10000, true, caster.getName())); + player.sendPacket(new ExSendUIEvent(player, ExSendUIEvent.TYPE_NORNIL, _chargedValues[index], 120, NpcStringId.CHARGING)); + }); + if (_chargedValues[index] >= 120) + { + _chargedMask |= 1 << index; + _chargedValues[index] = 0; + } + + if (hasFlag(_chargedMask, 0xf)) + { + nextStage(3); + } + } + } + } + return null; + } + + @Override + public String onSpawn(L2Npc npc) + { + switch (npc.getId()) + { + case NPC_ATTACKER_GENERATORS: + case NPC_ATTACKER_GENERATORS_1: + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2GuardInstance.class, 800, cha -> + { + + if (cha.getId() == GENERATOR_GUARD) + { + npc.reduceCurrentHp(1, cha, null); + cha.reduceCurrentHp(1, npc, null); + } + if (cha.getId() == NPC_GENERATOR) + { + ((L2Attackable) npc).addDamageHate(cha, 500, 98); + } + }); + break; + } + case LYN_DRACO_ATTACKER_GENERATORS: + { + ((L2Attackable) npc).setCanStopAttackByTime(false); + ((L2Attackable) npc).setCanReturnToSpawnPoint(false); + startQuestTimer("attack_generator", 10000, npc, null, true); + break; + } + case GENERATOR_GUARD: + { + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + ((L2GuardInstance) npc).setIsInvul(true); + break; + } + case NPC_GENERATOR: + { + npc.disableCoreAI(true); + npc.setDisplayEffect(1); + npc.setRandomWalking(false); + npc.setIsInvul(true); // Can't get damage now + _activeMask = 0; + _chargedMask = 0; + break; + } + } + return super.onSpawn(npc); + } + + @Override + public String onSeeCreature(L2Npc npc, L2Character player, boolean isSummon) + { + setLindviorSpawnTask(); + npc.getSpawn().stopRespawn(); + npc.deleteMe(); + return super.onSeeCreature(npc, player, isSummon); + } + + private void nextStage(int _taskId) + { + switch (_taskId) + { + case 1: // Spawn Generators + { + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, true)); + int i = 0; + L2GuardInstance guard; + for (Location loc : CONTROL_GENERATOR_SPAWNS) + { + guard = (L2GuardInstance) addSpawn(NPC_GENERATOR, loc, true); + guard.setDisplayEffect(0x01); + guard.setScriptValue(i++); + _generatorSpawn.add(guard); + } + + L2Npc npc; + for (Location loc : SCHEME_GENERATOR_SPAWNS) + { + npc = addSpawn(GENERATOR_GUARD, loc, true); + npc.setRandomWalking(false); + _guardSpawn.add(npc); + } + + _mobsSpawnTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : ATTACKER_GENERATOR_SPAWNS) + { + if (getRandom(10) <= 5) + { + _monsterSpawn.add(addSpawn(NPC_ATTACKER_GENERATORS, loc, true)); + } + else + { + _monsterSpawn.add(addSpawn(NPC_ATTACKER_GENERATORS_1, loc, true)); + } + } + }, 30000, 80000); + + _dummyLindvior = addSpawn(LINDVIOR_CAMERA, 45259, -27115, -638, 41325, false, 0, false); + _announceTask = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(player -> player.sendPacket(new ExShowScreenMessage(NpcStringId.YOU_MUST_ACTIVATE_THE_4_GENERATORS, ExShowScreenMessage.TOP_CENTER, 7000, true))), 10000, 20000); + break; + } + case 2: // After activation of 4 generators, we wait to be charged + { + if (_announceTask != null) + { + _announceTask.cancel(true); + _announceTask = null; + } + _generatorSpawn.forEach(npc -> + { + npc.setDisplayEffect(1); + npc.setIsInvul(false); + npc.broadcastInfo(); + }); + + _zoneLair.getPlayersInside().forEach(player -> + { + player.sendPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, false)); + cancelQuestTimers("NPC_SHOUT"); + _guardSpawn.stream().forEach(guard -> + { + guard.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.ALL_4_GENERATORS_MUST_BE_ACTIVATED); + }); + _announceProtect = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(p -> player.sendPacket(new ExShowScreenMessage(NpcStringId.PROTECT_THE_GENERATOR, ExShowScreenMessage.TOP_CENTER, 7000, true))), 10000, 18000); + _zoneLair.broadcastPacket(new SpecialCamera(_dummyLindvior, 3300, 200, 20, 11000, 10500, 0, 8, 1, 0, 0)); + _generatorSpawn.forEach(npc -> npc.sendInfo(player)); + startQuestTimer("show_movie", 13000, null, null); + startQuestTimer("start_charge", 35000, null, null); + startQuestTimer("show_shield_animation", 2000, null, null); + }); + break; + } + case 3: // After charging all the generators + { + _zoneLair.broadcastPacket(new OnEventTrigger(ALL_GENERATORS_CONNECTED_EFFECT, true)); + if (_announceTask != null) + { + _announceTask.cancel(true); + _announceTask = null; + } + if (_announceProtect != null) + { + _announceProtect.cancel(false); + _announceProtect = null; + } + if (_skillCastTask != null) + { + _skillCastTask.cancel(true); + _skillCastTask = null; + } + if (_LynDracoTask != null) + { + _LynDracoTask.cancel(true); + _LynDracoTask = null; + } + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(true); + _mobsSpawnTask = null; + } + _monsterSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _LinDracoSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _generatorSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _guardSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + cancelQuestTimers("attack_generator"); + _lindvior2.setIsDead(true); + _lindvior2.deleteMe(); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, FIGHTING); + _lionel = addSpawn(LIONEL_HUNTER, 42630, -48231, -792, 855, false, 0, false); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_GROUND, CENTER_LOCATION, false, 0, true); + _zoneLair.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _zoneLair.getPlayersInside().forEach(_lindvior::sendInfo); + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.LINDVIOR_HAS_FALLEN_FROM_THE_SKY, ExShowScreenMessage.TOP_CENTER, 7000)); + _mobsSpawnTask = ThreadPoolManager.scheduleAtFixedRate(() -> spawnServitor(2, 1000, _lindvior.getLocation(), LINDVIOR_SERVITOR), 60000, 180000); + break; + } + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + switch (event) + { + case "unlock_lindvior": + { + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, ALIVE); + break; + } + case "stage_1_activate_generator": + { + int index = npc.getScriptValue(); + if (!hasFlag(_activeMask, 1 << index)) + { + _activeMask |= 1 << index; + npc.setDisplayEffect(0x02); + sendEventTrigger(true, GENERATOR_TRIGERS[index]); + _zoneLair.getPlayersInside().stream().forEach(p -> p.broadcastPacket(new Earthquake(p.getX(), p.getY(), p.getZ(), 20, 10))); + if (hasFlag(_activeMask, 0xf)) + { + nextStage(2); + } + } + break; + } + case "show_shield_animation": // zone brodcat shield event triger + { + _zoneLair.getPlayersInside().forEach(p -> + { + p.sendPacket(new OnEventTrigger(SECOND_STAGE_EVENT_TRIGGER, true)); + }); + _guardSpawn.stream().forEach(guard -> + { + guard.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.THE_GENERATOR_IS_CONNECTED_TO_THE_CANNON); + }); + break; + } + case "show_movie": // zone brodcat Lindvior scene movie + { + _zoneLair.getPlayersInside().forEach(p -> + { + playMovie(p, Movie.SC_LIND_OPENING); + }); + _dummyLindvior.deleteMe(); + _lindvior2 = addSpawn(LINDVIOR_FAKE, CENTER_LOCATION, false, 0, false); + _lindvior2.setTargetable(false); + _announceTask = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(p -> p.sendPacket(new ExShowScreenMessage(NpcStringId.CHARGE_THE_CANNON_USING_THE_GENERATOR, ExShowScreenMessage.TOP_CENTER, 7000, true))), 40000, 20000); + break; + } + case "start_charge": + { + _skillCastTask = ThreadPoolManager.scheduleAtFixedRate(() -> _generatorSpawn.forEach(generators -> + { + int index = generators.getScriptValue(); + if (!generators.isCastingNow() && (generators.getEffectList().getBuffInfoBySkillId(SKILL_RECHARGE_POSIBLE.getSkillId()) == null) && !hasFlag(_chargedMask, 1 << index)) + { + // TODO Need core implemented combo skill packet. + // On this moment player automatic charge generator if distance generator and player <= 900 + generators.doCast(SKILL_RECHARGE_POSIBLE.getSkill()); + L2World.getInstance().forEachVisibleObjectInRange(generators, L2PcInstance.class, 900, p -> + { + p.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + p.setTarget(generators); + p.doCast(RECHARGE.getSkill()); + }); + _guardSpawn.stream().forEach(guard -> + { + guard.setTarget(generators); + guard.doCast(RECHARGE.getSkill()); + guard.setIsInvul(false); + if (!guard.isDead()) + { + guard.broadcastSay(ChatType.NPC_GENERAL, GUARD_MSG_1[getRandom(GUARD_MSG_1.length)]); + } + }); + } + }), 10000, 20000); + _LynDracoTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : LYN_DRACO_SPAWNS) + { + _LinDracoSpawn.add(addSpawn(LYN_DRACO_ATTACKER_GENERATORS, loc, true)); + } + }, 20000, 60000); + break; + } + case "stop_red_zone": + { + _zoneLair.broadcastPacket(new OnEventTrigger(RED_ZONE_EFFECT, false)); + break; + } + case "attack_generator": + { + if ((npc != null) && !npc.isDead()) + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2GuardInstance.class, 3000, generator -> + { + if (generator.getId() == NPC_GENERATOR) + { + npc.setTarget(generator); + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, generator.getLocation()); + if (npc.distFromMe(generator) < 500) + { + npc.reduceCurrentHp(1, generator, null); + generator.reduceCurrentHp(1, npc, null); + } + } + }); + } + break; + } + } + return null; + } + + @Override + public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon) + { + if (npc.getId() == LINDVIOR_RAID) + { + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.HONORABLE_WARRIORS_HAVE_DRIVEN_OFF_LINDVIOR_THE_EVIL_WIND_DRAGON, ExShowScreenMessage.TOP_CENTER, 10000, true)); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, DEAD); + final long respawnTime = (Config.LINDVIOR_SPAWN_INTERVAL + getRandom(-Config.LINDVIOR_SPAWN_RANDOM, Config.LINDVIOR_SPAWN_RANDOM)) * 3600000; + final StatsSet info = GrandBossManager.getInstance().getStatsSet(LINDVIOR_RAID); + info.set("respawn_time", System.currentTimeMillis() + respawnTime); + GrandBossManager.getInstance().setStatsSet(LINDVIOR_RAID, info); + startQuestTimer("unlock_lindvior", respawnTime, null, null); + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(true); + _mobsSpawnTask = null; + } + _zoneLair.getCharactersInside().stream().filter(L2Character::isNpc).forEach(mob -> mob.deleteMe()); + ThreadPoolManager.schedule(() -> npc.decayMe(), 10000); + _zoneLair.broadcastPacket(new OnEventTrigger(SECOND_STAGE_EVENT_TRIGGER, false)); + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, true)); + _lionel.deleteMe(); + } + else if (npc.getId() == NPC_GENERATOR) + { + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.THE_GENERATOR_HAS_BEEN_DESTROYED, ExShowScreenMessage.TOP_CENTER, 5000, true)); + Clean(); + _collapseTask = ThreadPoolManager.schedule(() -> Fail(false), 20000); + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onFirstTalk(L2Npc npc, L2PcInstance player) + { + if (npc.getId() == NPC_GENERATOR) + { + return npc.getDisplayEffect() == 1 ? "19477.html" : "19477-01.html"; + } + return super.onFirstTalk(npc, player); + } + + @Override + public String onEnterZone(L2Character character, L2ZoneType zone) + { + if (zone.getId() == ZONE_ID) + { + if (_collapseTask != null) + { + _collapseTask.cancel(true); + _collapseTask = null; + } + } + return super.onEnterZone(character, zone); + } + + @Override + public String onExitZone(L2Character character, L2ZoneType zone) + { + if (zone.getId() == ZONE_ID) + { + if (zone.getPlayersInside().isEmpty()) + { + _collapseTask = ThreadPoolManager.schedule(() -> Fail(true), 900000); + } + } + return super.onExitZone(character, zone); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + if (event.equals("NPC_SHOUT")) + { + if ((npc != null) && !npc.isDead()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, GUARD_MSG[getRandom(GUARD_MSG.length)]); + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + } + } + } + + private void sendEventTrigger(boolean status, int... triggers) + { + IClientOutgoingPacket[] pakets = new IClientOutgoingPacket[triggers.length]; + for (int i = 0; i < triggers.length; i++) + { + pakets[i] = new OnEventTrigger(triggers[i], status); + } + for (IClientOutgoingPacket packet : pakets) + { + _zoneLair.broadcastPacket(packet); + } + } + + private void spawnServitor(int count, int radius, Location loc, int... npcIds) + { + int x = loc.getX(), y = loc.getY(); + if (radius > 0) + { + x += Rnd.get(-radius, radius); + y += Rnd.get(-radius, radius); + } + + for (int i = 0; i < count; i++) + { + _monsterSpawn.add(addSpawn(npcIds[getRandom(npcIds.length)], x, y, loc.getZ(), loc.getHeading(), true, 0, true)); + } + } + + private static boolean hasFlag(int val, int flag) + { + return (val & flag) == flag; + } + + public void setLindviorSpawnTask() + { + synchronized (this) + { + if (_socialTask == null) + { + _socialTask = ThreadPoolManager.schedule(() -> nextStage(1), 3000); + } + } + } + + @RegisterEvent(EventType.ON_CREATURE_DAMAGE_RECEIVED) + @RegisterType(ListenerRegisterType.NPC) + @Id(LINDVIOR_FLY) + @Id(LINDVIOR_RAID) + @Id(LINDVIOR_GROUND) + public void onCreatureDamageReceived(OnCreatureDamageReceived event) + { + _zoneLair.getPlayersInside().stream().forEach(p -> + { + switch (_status) + { + case 0: + case 1: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 1, -1, 0.015, true); + break; + } + case 2: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 2, -1, 0.015, true); + break; + } + case 3: + case 4: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 3, -1, 0.015, true); + break; + } + case 5: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 4, -1, 0.015, true); + break; + } + } + }); + } + + public static void main(String[] args) + { + new Lindvior(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java new file mode 100644 index 0000000000..d60c088f9f --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java @@ -0,0 +1,175 @@ +/* + * 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 ai.bosses.Lindvior; + +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.SkillHolder; + +import ai.AbstractNpcAI; + +/** + * LindviorBoss AI + * @author Gigi + * @date 2017-08-02 - [11:05:21] + */ +public class LindviorBoss extends AbstractNpcAI +{ + // Boss + private static final int LINDVIOR_GROUND = 25899; + private static final int LINDVIOR_RAID = 29240; + private static final int LINDVIOR_FLY = 19424; + // Skills + private static final SkillHolder SKILL_FLY_UP = new SkillHolder(15278, 1); + private static final SkillHolder SKILL_RABIES = new SkillHolder(15269, 1); + private static final SkillHolder SKILL_FLY = new SkillHolder(15279, 1); + private static final SkillHolder MASS_HELL_BINDING = new SkillHolder(11052, 6); + private static final SkillHolder MIGHTY_WIND_STRIKE = new SkillHolder(15274, 1); + private static final SkillHolder WIND_PULL = new SkillHolder(15591, 1); + private static final SkillHolder LINDVIORS_JUMP = new SkillHolder(15430, 1); + private static final SkillHolder BODY_SLAM = new SkillHolder(15271, 1); + private static final SkillHolder SOAR = new SkillHolder(15279, 1); + private static final SkillHolder WIND_BREAT = new SkillHolder(15272, 1); + private static final SkillHolder TAIL_SWIPE = new SkillHolder(15273, 1); + private static final SkillHolder TORNADO = new SkillHolder(15275, 1); + private static final SkillHolder LINDVIORS_ATTACK = new SkillHolder(15600, 1); + // Chances + private final static int CHANCE_MIGHTY_WIND_STRIKE = 9; + private final static int CHANCE_WIND_PULL = 4; + private final static int CHANCE_LINDVIORS_JUMP = 7; + private final static int CHANCE_BODY_SLAM = 2; + private final static int CHANCE_SOAR = 8; + private final static int CHANCE_WIND_BREAT = 3; + private final static int CHANCE_TAIL_SWIPE = 5; + private final static int CHANCE_TORNADO = 6; + private final static int CHANCE_LINDVIORS_ATTACK = 1; + + public LindviorBoss() + { + super(); + addAttackId(LINDVIOR_GROUND, LINDVIOR_FLY, LINDVIOR_RAID); + addSpawnId(LINDVIOR_FLY); + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + double percent = ((npc.getCurrentHp() - damage) / npc.getMaxHp()) * 100; + final int chance = getRandom(100); + switch (npc.getId()) + { + case LINDVIOR_GROUND: + { + if ((percent <= 80) && npc.isScriptValue(0)) + { + + npc.doCast(SKILL_FLY_UP.getSkill()); + npc.doCast(SKILL_RABIES.getSkill()); + npc.setScriptValue(1); + } + else if ((percent <= 40) && (npc.isScriptValue(1))) + { + npc.doCast(SKILL_FLY.getSkill()); + npc.setScriptValue(2); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_MIGHTY_WIND_STRIKE)) + { + npc.setTarget(attacker); + npc.doCast(MIGHTY_WIND_STRIKE.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_PULL)) + { + npc.setTarget(attacker); + npc.doCast(WIND_PULL.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_LINDVIORS_JUMP)) + { + npc.setTarget(attacker); + npc.doCast(LINDVIORS_JUMP.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_BODY_SLAM)) + { + npc.setTarget(attacker); + npc.doCast(BODY_SLAM.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TAIL_SWIPE)) + { + npc.setTarget(attacker); + npc.doCast(TAIL_SWIPE.getSkill()); + } + break; + } + case LINDVIOR_FLY: + { + if (!npc.isCastingNow() && (chance <= CHANCE_SOAR)) + { + npc.setTarget(attacker); + npc.doCast(SOAR.getSkill()); + } + break; + } + case LINDVIOR_RAID: + { + if ((percent <= 20) && (npc.isScriptValue(0))) + { + npc.doCast(SKILL_FLY.getSkill()); + npc.setScriptValue(1); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_BREAT)) + { + npc.setTarget(attacker); + npc.doCast(WIND_BREAT.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_PULL)) + { + npc.setTarget(attacker); + npc.doCast(WIND_PULL.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TAIL_SWIPE)) + { + npc.setTarget(attacker); + npc.doCast(TAIL_SWIPE.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TORNADO)) + { + npc.setTarget(attacker); + npc.doCast(TORNADO.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_LINDVIORS_ATTACK)) + { + npc.setTarget(attacker); + npc.doCast(LINDVIORS_ATTACK.getSkill()); + } + break; + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + npc.setRandomWalking(true); + npc.doCast(MASS_HELL_BINDING.getSkill()); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new LindviorBoss(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java new file mode 100644 index 0000000000..846ada3442 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java @@ -0,0 +1,67 @@ +/* + * 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 ai.bosses.Lindvior; + +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.instancemanager.WalkingManager; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.NpcStringId; + +import ai.AbstractNpcAI; + +/** + * Lionel Hunter AI + * @author Gigi + * @date 2017-07-23 - [22:54:59] + */ +public class LionelHunter extends AbstractNpcAI +{ + // Npc + private static final int LIONEL_HUNTER = 33886; + // Misc + private static final String ROUTE_NAME = "Rune_Lionel"; + + public LionelHunter() + { + addSpawnId(LIONEL_HUNTER); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + if (event.equals("NPC_SHOUT") && (npc != null)) + { + npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.WE_JUST_LOCATED_LINDVIOR_THOSE_WHO_ARE_WILLING_TO_FIGHT_CAN_DO_SO_AT_ANY_TIME_NOW); + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + } + } + + @Override + public String onSpawn(L2Npc npc) + { + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + WalkingManager.getInstance().startMoving(npc, ROUTE_NAME); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new LionelHunter(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java new file mode 100644 index 0000000000..d9bf024d24 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java @@ -0,0 +1,176 @@ +/* + * 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 ai.bosses.Lindvior; + +import java.util.Collection; + +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.serverpackets.FlyToLocation; +import com.l2jmobius.gameserver.network.serverpackets.ValidateLocation; + +import ai.AbstractNpcAI; + +/** + * Vortex AI + * @author Gigi + * @date 2017-07-23 - [10:32:50] + */ +public class Vortex extends AbstractNpcAI +{ + private static final int SMALL_VORTEX = 25898; + private static final int BIG_VORTEX = 19427; + + public Vortex() + { + super(); + addSeeCreatureId(SMALL_VORTEX, BIG_VORTEX); + addSpawnId(SMALL_VORTEX, BIG_VORTEX); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + switch (event) + { + case "rnd_small": + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 250, attackers -> + { + if ((attackers != null) && !attackers.isDead() && !attackers.isAlikeDead()) + { + attackers.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + final int radians = (int) Math.toRadians(npc.calculateDirectionTo(attackers)); + final int x = (int) (attackers.getX() + (600 * Math.cos(radians))); + final int y = (int) (attackers.getY() + (600 * Math.sin(radians))); + final int z = attackers.getZ(); + final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld()); + attackers.broadcastPacket(new FlyToLocation(attackers, x, y, z, FlyToLocation.FlyType.THROW_UP, 800, 800, 800)); + attackers.setXYZ(loc); + attackers.broadcastPacket(new ValidateLocation(attackers)); + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player); + startQuestTimer("stop_knock_down", 5000, npc, attackers); + startQuestTimer("despawn_small", 5000, npc, null); + } + }); + break; + } + case "rnd_big": + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 500, attackers -> + { + if ((attackers != null) && !attackers.isDead() && !attackers.isAlikeDead()) + { + attackers.setCurrentHp(1.0); + attackers.setCurrentMp(1.0); + attackers.setCurrentCp(1.0); + startQuestTimer("despawn_big", 600000, npc, null); + } + }); + break; + } + case "despawn_small": + { + if (npc != null) + { + cancelQuestTimers("rnd_small"); + npc.getSpawn().stopRespawn(); + npc.doDie(null); + } + break; + } + case "despawn_big": + { + if (npc != null) + { + cancelQuestTimers("despawn_big"); + npc.getSpawn().stopRespawn(); + npc.deleteMe(); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSeeCreature(L2Npc npc, L2Character player, boolean isSummon) + { + switch (npc.getId()) + { + case SMALL_VORTEX: + { + startQuestTimer("rnd_small", 5000, npc, null, true); + break; + } + case BIG_VORTEX: + { + startQuestTimer("rnd_big", 10000, npc, null, true); + break; + } + } + return super.onSeeCreature(npc, player, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + switch (npc.getId()) + { + case SMALL_VORTEX: + { + attackRandomTarget(npc); + npc.setRandomWalking(true); + npc.setIsRunning(true); + break; + } + case BIG_VORTEX: + { + attackRandomTarget(npc); + npc.setRandomWalking(true); + npc.setIsRunning(true); + break; + } + } + return super.onSpawn(npc); + } + + private void attackRandomTarget(L2Npc npc) + { + final Collection players = L2World.getInstance().getVisibleObjects(npc, L2PcInstance.class); + { + if ((players == null) || players.isEmpty()) + { + return; + } + if (players.size() > 0) + { + addAttackPlayerDesire(npc, players.stream().findAny().get()); + } + } + } + + public static void main(String[] args) + { + new Vortex(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/08500-08599.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/08500-08599.xml index 759a91fb29..bbcefbf96b 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/08500-08599.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/08500-08599.xml @@ -1954,7 +1954,7 @@ - + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19400-19499.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19400-19499.xml index 8d70de0309..bc7107be8a 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19400-19499.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19400-19499.xml @@ -825,58 +825,76 @@ - + DRAGON FEMALE - - - + + - + - - + + - + + - - + - - + + + + + + + + + + - + DRAGON FEMALE - - - + + - + - - + + - + + - - + - - - + + + + + + + + + + + + + + + @@ -984,7 +1002,7 @@ - + @@ -2357,7 +2375,7 @@ - + ETC FEMALE @@ -2373,7 +2391,10 @@ - + + + + @@ -2401,7 +2422,7 @@ - + ETC FEMALE @@ -2412,7 +2433,7 @@ - + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/25800-25899.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/25800-25899.xml index 7f8dad3878..22cc2e00b9 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/25800-25899.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/25800-25899.xml @@ -4791,7 +4791,7 @@ - + DRAGON FEMALE @@ -4801,8 +4801,8 @@ - - + + @@ -4822,7 +4822,7 @@ - + DRAGON FEMALE @@ -4853,7 +4853,7 @@ - + DRAGON FEMALE @@ -4877,6 +4877,12 @@ + + + + + + @@ -4884,15 +4890,18 @@ - + + + + DRAGON FEMALE - - + + @@ -4910,29 +4919,29 @@ - + true + - - + DRAGON FEMALE - - + + + - - + + - - + + - @@ -4941,11 +4950,16 @@ + + + + + - - + + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/29200-29299.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/29200-29299.xml index 21fb5237c1..aa344a1818 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/29200-29299.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/29200-29299.xml @@ -2018,13 +2018,13 @@ - - + DRAGON FEMALE + - + @@ -2038,9 +2038,19 @@ - - - + + + + + + + + + + + + + @@ -2135,7 +2145,7 @@ - + DRAGON FEMALE diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/skills/15600-15699.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/skills/15600-15699.xml index 89ca9ee0d9..321cb09e4a 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/skills/15600-15699.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/skills/15600-15699.xml @@ -49,23 +49,38 @@ 2 1800 - - + icon.skill0005 + 20 A2 + 1000 + 1000 1 - 25000 + 10000 + SELF + RANGE + NOT_FRIEND - icon.skill1449 + icon.skill14444 A1 + 1 900 10000 -2 - 200 + 200 + TARGET + SINGLE + + + + 19477 + + + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/no_summon_friend.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/no_summon_friend.xml index a6b09689a0..7b5203b963 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/no_summon_friend.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/no_summon_friend.xml @@ -167,4 +167,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java index 40be605ad7..e450b23b2f 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java @@ -891,6 +891,13 @@ public final class Config public static int KELBIM_SPAWN_INTERVAL; public static int KELBIM_SPAWN_RANDOM; + // Lindvior + public static int LINDVIOR_SPAWN_INTERVAL; + public static int LINDVIOR_SPAWN_RANDOM; + public static int LINDVIOR_MIN_PLAYERS; + public static int LINDVIOR_MAX_PLAYERS; + public static int LINDVIOR_MIN_PLAYER_LVL; + // Anakim public static int ANAKIM_MIN_PLAYERS; public static int ANAKIM_MAX_PLAYERS; @@ -2223,6 +2230,11 @@ public final class Config LILITH_SPAWN_RANDOM = GrandBossSettings.getInt("RandomOfLilithSpawn", 148); LILITH_MIN_PLAYER_LVL = GrandBossSettings.getInt("LilithMinPlayerLvl", 85); LILITH_MAX_PLAYER_LVL = GrandBossSettings.getInt("LilithMaxPlayerLvl", 89); + LINDVIOR_SPAWN_INTERVAL = GrandBossSettings.getInt("IntervalOfLindviorSpawn", 264); + LINDVIOR_SPAWN_RANDOM = GrandBossSettings.getInt("RandomOfLindviorSpawn", 72); + LINDVIOR_MIN_PLAYERS = GrandBossSettings.getInt("LindviorMinPlayers", 49); + LINDVIOR_MAX_PLAYERS = GrandBossSettings.getInt("LindviorMaxPlayers", 112); + LINDVIOR_MIN_PLAYER_LVL = GrandBossSettings.getInt("LindviorMinPlayerLvl", 99); // Gracia Seeds final PropertiesParser GraciaSeedsSettings = new PropertiesParser(GRACIASEEDS_CONFIG_FILE); diff --git a/L2J_Mobius_1.0_Ertheia/readme.txt b/L2J_Mobius_1.0_Ertheia/readme.txt index f6a9bfe6ad..0b4eeb2a37 100644 --- a/L2J_Mobius_1.0_Ertheia/readme.txt +++ b/L2J_Mobius_1.0_Ertheia/readme.txt @@ -20,7 +20,6 @@ What is done TODO -Modify all skill levels/sublevels based on client --Lindvior -Trasken -Kamaloka -Provisional Clan Halls diff --git a/L2J_Mobius_2.5_Underground/dist/db_installer/sql/game/grandboss_data.sql b/L2J_Mobius_2.5_Underground/dist/db_installer/sql/game/grandboss_data.sql index 27ff367d22..68a2deaa1e 100644 --- a/L2J_Mobius_2.5_Underground/dist/db_installer/sql/game/grandboss_data.sql +++ b/L2J_Mobius_2.5_Underground/dist/db_installer/sql/game/grandboss_data.sql @@ -17,9 +17,10 @@ INSERT IGNORE INTO `grandboss_data` (`boss_id`,`loc_x`,`loc_y`,`loc_z`,`heading` (29006, 17726, 108915, -6480, 0, 622493.58388, 3793.536), -- Core (29014, 55024, 17368, -5412, 10126, 622493.58388, 3793.536), -- Orfen (29020, 116033, 17447, 10107, -25348, 4068372, 39960), -- Baium -(29028, -105200, -253104, -15264, 0, 62041918, 2248572), -- Valakas (29068, 185708, 114298, -8221,32768, 62802301, 1998000), -- Antharas +(29028, -105200, -253104, -15264, 0, 62041918, 2248572), -- Valakas +(29240, 0, 0, 0, 0, 288282589, 47100), -- Lindvior (29118, 0, 0, 0, 0, 4109288, 1220547), -- Beleth (25286, 185080, -12613, -5499, 16550, 556345880, 86847), -- Anakim (25283, 185062, -9605, -5499, 15640, 486021997, 79600), -- Lilith -(26124, 0, 0, 0, 0, 13945521, 50920); -- Kelbim \ No newline at end of file +(26124, 0, 0, 0, 0, 13945521, 50920); -- Kelbim diff --git a/L2J_Mobius_2.5_Underground/dist/game/config/GrandBoss.ini b/L2J_Mobius_2.5_Underground/dist/game/config/GrandBoss.ini index 21b6037556..3689173278 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/config/GrandBoss.ini +++ b/L2J_Mobius_2.5_Underground/dist/game/config/GrandBoss.ini @@ -144,4 +144,23 @@ LilithMaxPlayers = 120 LilithMinPlayerLvl = 85 # Maximum players Level for enter to Lilith. Retail: 89 -LilithMaxPlayerLvl = 89 \ No newline at end of file +LilithMaxPlayerLvl = 89 + +# --------------------------------------------------------------------------- +# Lindvior +# --------------------------------------------------------------------------- + +# Interval time of Lindvior. Value is hour. Range 1-480. Retail: 264 +IntervalOfLindviorSpawn = 264 + +# Random interval. Range 1-192. Retail: 72 +RandomOfLindviorSpawn = 72 + +# Minimal count of players for enter to Lindvior. Retail: 49 +LindviorMinPlayers = 49 + +# Maximum count of players for enter to Lindvior. Retail: 112 +LindviorMaxPlayers = 112 + +# Minimum players Level for enter to Lindvior. Retail: 99 +LindviorMinPlayerLvl = 99 \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml index 5cbbf5261f..dc0e5372c2 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml @@ -2352,4 +2352,8 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java index 790799b0ad..b1a37e194f 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java @@ -75,7 +75,7 @@ public class AltarOfSacrifice extends AbstractNpcAI @Override public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon) { - if (creature.isPlayer() && _jenas_guard.isScriptValue(0)) + if ((creature != null) && creature.isPlayer() && _jenas_guard.isScriptValue(0)) { startQuestTimer("msg_text", 3000, npc, null); _jenas_guard.setScriptValue(1); diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html new file mode 100644 index 0000000000..5f9fc4431e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html @@ -0,0 +1,3 @@ +Generator:
+The generator is now supplying power to the sealed structure. + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477.html new file mode 100644 index 0000000000..540ff6ac54 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/19477.html @@ -0,0 +1,3 @@ +Generator:

+ + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html new file mode 100644 index 0000000000..ba01eab970 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+On the Lindvior there is an attack!
+At this time it's impossible to enter the altar. + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html new file mode 100644 index 0000000000..e3eac44ec7 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+Lindvior? You're too late, friend.
+A group of warriors drove him off not long ago. + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html new file mode 100644 index 0000000000..40de9b961e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+You are overcome by a voice, a voice so powerful you are helpless as it speaks:
+(The players who belong to an association can only enter through the Association Leader.) + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html new file mode 100644 index 0000000000..9af5ff8c7a --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html @@ -0,0 +1,3 @@ +Rune Castle Patrol Kato:
+(A command channel needs at least minimu: %min% and maximum: %max% members to challenge Lindvior.) + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html new file mode 100644 index 0000000000..309c938f02 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html @@ -0,0 +1,3 @@ +Rune Castle Patrol Kato:
+(A command channel members level must be minimum: %minlvl% Lvl or higher to challenge Lindvior.) + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html new file mode 100644 index 0000000000..bddff0b348 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html @@ -0,0 +1,6 @@ +Rune Castle Patrol Kato:
+Dire times dictated that I come myself from Rune Castle to help those in need here.
+What do you need?
+ + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java new file mode 100644 index 0000000000..3b54f9dfa8 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java @@ -0,0 +1,129 @@ +/* + * 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 ai.bosses.Lindvior.KatoSicanus; + +import java.util.List; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.instancemanager.GrandBossManager; +import com.l2jmobius.gameserver.model.L2Party; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; + +import ai.AbstractNpcAI; + +/** + * Kato Sicanus Teleporter AI + * @author Gigi + * @date 2017-07-13 - [22:17:16] + */ +public class KatoSicanus extends AbstractNpcAI +{ + // NPCs + private static final int KATO_SICANUS = 33881; + private static final int LINDVIOR_RAID = 29240; + private static final int INVISIBLE = 8572; + // Location + private static final Location LINDVIOR_LOCATION = new Location(46929, -28807, -1400); + + public KatoSicanus() + { + addFirstTalkId(KATO_SICANUS); + addTalkId(KATO_SICANUS); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.equals("teleport")) + { + final int status = GrandBossManager.getInstance().getBossStatus(LINDVIOR_RAID); + if (player.isGM()) + { + player.teleToLocation(LINDVIOR_LOCATION, true); + addSpawn(INVISIBLE, 46707, -28586, -1400, 0, false, 60000, false); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, 1); + } + else + { + if (status == 2) + { + return "33881-1.html"; + } + if (status == 3) + { + return "33881-2.html"; + } + if (!player.isInParty()) + { + return "33881-3.html"; + } + final L2Party party = player.getParty(); + final boolean isInCC = party.isInCommandChannel(); + final List members = (isInCC) ? party.getCommandChannel().getMembers() : party.getMembers(); + final boolean isPartyLeader = (isInCC) ? party.getCommandChannel().isLeader(player) : party.isLeader(player); + if (!isPartyLeader) + { + return "33881-3.html"; + } + if ((members.size() < Config.LINDVIOR_MIN_PLAYERS) || (members.size() > Config.LINDVIOR_MAX_PLAYERS)) + { + final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId()); + packet.setHtml(getHtm(player.getHtmlPrefix(), "33881-4.html")); + packet.replace("%min%", Integer.toString(Config.LINDVIOR_MIN_PLAYERS)); + packet.replace("%max%", Integer.toString(Config.LINDVIOR_MAX_PLAYERS)); + player.sendPacket(packet); + return null; + } + for (L2PcInstance member : members) + { + if (member.getLevel() < Config.LINDVIOR_MIN_PLAYER_LVL) + { + final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId()); + packet.setHtml(getHtm(player.getHtmlPrefix(), "33881-5.html")); + packet.replace("%minlvl%", Integer.toString(Config.LINDVIOR_MIN_PLAYER_LVL)); + player.sendPacket(packet); + return null; + } + } + for (L2PcInstance member : members) + { + if (member.isInsideRadius(npc, 1500, true, false)) + { + member.teleToLocation(LINDVIOR_LOCATION, true); + addSpawn(INVISIBLE, 46707, -28586, -1400, 0, false, 0, false); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, 1); + } + } + } + } + return null; + } + + @Override + public String onFirstTalk(L2Npc npc, L2PcInstance player) + { + return "33881.html"; + } + + public static void main(String[] args) + { + new KatoSicanus(); + } +} diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java new file mode 100644 index 0000000000..d6247a96c6 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java @@ -0,0 +1,976 @@ +/* + * 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 ai.bosses.Lindvior; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledFuture; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.enums.Movie; +import com.l2jmobius.gameserver.instancemanager.GrandBossManager; +import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance; +import com.l2jmobius.gameserver.model.actor.instance.L2GuardInstance; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.events.EventType; +import com.l2jmobius.gameserver.model.events.ListenerRegisterType; +import com.l2jmobius.gameserver.model.events.annotations.Id; +import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent; +import com.l2jmobius.gameserver.model.events.annotations.RegisterType; +import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureDamageReceived; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.Skill; +import com.l2jmobius.gameserver.model.zone.L2ZoneType; +import com.l2jmobius.gameserver.model.zone.type.L2NoSummonFriendZone; +import com.l2jmobius.gameserver.network.NpcStringId; +import com.l2jmobius.gameserver.network.serverpackets.Earthquake; +import com.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import com.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; +import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; +import com.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; +import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera; + +import ai.AbstractNpcAI; + +/** + * Lindvior Boss + * @author Gigi + * @date 2017-07-11 - [17:42:53] + *

+ * @VIDEO - https://www.youtube.com/watch?v=VknjOjRO9Cw + */ +public class Lindvior extends AbstractNpcAI +{ + // Monsters + private static final int LINDVIOR_FAKE = 19423; + private static final int LINDVIOR_GROUND = 25899; + private static final int LINDVIOR_RAID = 29240; + private static final int LINDVIOR_FLY = 19424; + private static final int NPC_GENERATOR = 19477; + private static final int GENERATOR_GUARD = 19479; + private static final int NPC_ATTACKER_GENERATORS = 25897; + private static final int NPC_ATTACKER_GENERATORS_1 = 25895; + private static final int LYN_DRACO_ATTACKER_GENERATORS = 29241; + private static final int NPC_ATTACKER_SMALL_VORTEX = 25898; + private static final int NPC_ATTACKER_BIG_VORTEX = 19427; + private static final int INVISIBLE = 8572; + private static final int LIONEL_HUNTER = 33886; + private static final int LINDVIOR_CAMERA = 19428; + // Zone + private final static int ZONE_ID = 12107; + static final Location CENTER_LOCATION = new Location(46424, -26200, -1400); + // Skills + private static final SkillHolder SKILL_RECHARGE_POSIBLE = new SkillHolder(15605, 1); + private static final SkillHolder RECHARGE = new SkillHolder(15606, 1); + private static final SkillHolder SKILL_REFLECT = new SkillHolder(15592, 1); + // Item + private static final int LINDVIORS_SCALE = 37495; + // Trigers + private static final int FIRST_STAGE_EVENT_TRIGGER = 21170112; + private static final int SECOND_STAGE_EVENT_TRIGGER = 21170100; + private static final int ALL_GENERATORS_CONNECTED_EFFECT = 21170110; + private static final int RED_ZONE_EFFECT = 21170120; + // Status + private static final int ALIVE = 0; + private static final int FIGHTING = 2; + private static final int DEAD = 3; + // Tasks + protected ScheduledFuture _socialTask; + protected ScheduledFuture _mobsSpawnTask; + protected ScheduledFuture _collapseTask; + protected ScheduledFuture _announceTask; + protected ScheduledFuture _announceProtect; + protected ScheduledFuture _skillCastTask; + protected ScheduledFuture _LynDracoTask; + protected ScheduledFuture _smallVortexesTask; + protected ScheduledFuture _bigVortexesTask; + protected L2NoSummonFriendZone _zoneLair; + protected L2GrandBossInstance _lindvior = null; + protected L2Npc _lindvior2 = null; + protected L2Npc _dummyLindvior; + protected L2Npc _vortex = null; + protected L2Npc _lionel = null; + protected List _guardSpawn = new ArrayList<>(); + protected List _generatorSpawn = new ArrayList<>(); + protected List _monsterSpawn = new ArrayList<>(); + protected List _LinDracoSpawn = new ArrayList<>(); + protected int _activeMask = 0; + protected int _chargedMask = 0; + protected int _status = 0; + + private static final Location[] CONTROL_GENERATOR_SPAWNS = + { + new Location(45288, -30360, -1432, 0), + new Location(48486, -27175, -1432, 0), + new Location(45272, -23976, -1432, 0), + new Location(42088, -27160, -1432, 0) + }; + private static final Location[] SCHEME_GENERATOR_SPAWNS = + { + new Location(48440, -26824, -1438, 0), + new Location(48392, -27448, -1438, 0), + new Location(42136, -27480, -1438, 0), + new Location(42136, -26840, -1438, 0), + new Location(44936, -24024, -1438, 0), + new Location(45592, -24008, -1438, 0), + new Location(45608, -30312, -1438, 0), + new Location(44984, -30360, -1438, 0) + }; + private static final Location[] ATTACKER_GENERATOR_SPAWNS = + { + new Location(44863, -24272, -1413, 33713), + new Location(45675, -24272, -1413, 33713), + new Location(45675, -30057, -1413, 64987), + new Location(44863, -30057, -1413, 64987), + new Location(42350, -27563, -1413, 46871), + new Location(42350, -26809, -1413, 46871), + new Location(48220, -26809, -1413, 16383), + new Location(48220, -27563, -1413, 16383) + }; + private static final Location[] LYN_DRACO_SPAWNS = + { + new Location(45300, -28402, -1400, 48845), + new Location(46379, -27178, -1400, 1154), + new Location(45292, -26043, -1400, 13027), + new Location(44215, -27172, -1400, 33966) + }; + private static final Location[] ATTACKER_SMALL_VORTEX_SPAWNS = new Location[] + { + new Location(46256, -30159, -1430, 57430), + new Location(45155, -29987, -1430, 14860), + new Location(46219, -27704, -1430, 1744), + new Location(46135, -28995, -1430, 43626), + new Location(43973, -28265, -1430, 16516), + new Location(46782, -29065, -1430, 63368), + new Location(47214, -29836, -1430, 46966), + new Location(44754, -29120, -1430, 56118), + new Location(47089, -28198, -1430, 8537), + new Location(44992, -28152, -1430, 11592), + new Location(44737, -24885, -1430, 3146), + new Location(46096, -24976, -1430, 49650), + new Location(46972, -25911, -1430, 62925), + new Location(46977, -27136, -1430, 2150), + new Location(42889, -24767, -1430, 10246), + new Location(47299, -25256, -1430, 1453), + new Location(44204, -25026, -1430, 39225), + new Location(42875, -28035, -1430, 34755), + new Location(41963, -26031, -1430, 18822), + new Location(43171, -25942, -1430, 44279), + new Location(41874, -27174, -1430, 56030), + new Location(44983, -26082, -1430, 7042), + new Location(46145, -26804, -1430, 24394), + new Location(46148, -26019, -1430, 34151), + new Location(45161, -24275, -1430, 39262), + new Location(47288, -24141, -1430, 21644), + new Location(43722, -26174, -1430, 11001), + new Location(44942, -27169, -1430, 39703), + new Location(46105, -24170, -1430, 28224), + new Location(49084, -27206, -1430, 41996), + new Location(48159, -27091, -1430, 62682), + new Location(48094, -28789, -1430, 49189), + new Location(48958, -27844, -1430, 59758), + new Location(43828, -23981, -1430, 10994), + new Location(48165, -25777, -1430, 53084), + new Location(48267, -28086, -1430, 9266), + new Location(43268, -28981, -1430, 23736), + new Location(44155, -29821, -1430, 39281), + new Location(43991, -29275, -1430, 27277), + new Location(44057, -27133, -1430, 64484), + new Location(43257, -26764, -1430, 14161), + new Location(42300, -25194, -1430, 7811), + new Location(42091, -27981, -1430, 30628), + new Location(47854, -24735, -1430, 14438) + }; + // @formatter:off + private static final int[][] GENERATOR_TRIGERS = + { + {21170102, 21170103}, + {21170104, 21170105}, + {21170106, 21170107}, + {21170108, 21170109} + }; + protected final int _chargedValues[] = new int[] {0, 0, 0, 0}; + private static final int[] LINDVIOR_SERVITOR = {25895, 25896, 25897, 29242, 29241, 29243}; + // @formatter:on + private static final NpcStringId[] GUARD_MSG = + { + NpcStringId.ACTIVATE_THE_GENERATOR_HURRY, + NpcStringId.WE_WILL_HOLD_OFF_LINDVIOR_S_MINIONS, + }; + private static final NpcStringId[] GUARD_MSG_1 = + { + NpcStringId.HOLD_ONTO_THE_GENERATOR_TO_ACTIVATE_THE_CHARGE_SKILL, + NpcStringId.THE_GENERATOR_IS_CONNECTED_TO_THE_CANNON, + }; + + public Lindvior() + { + super(); + addAttackId(LINDVIOR_GROUND, LINDVIOR_FLY, LINDVIOR_RAID); + addEnterZoneId(ZONE_ID); + addExitZoneId(ZONE_ID); + addKillId(LINDVIOR_RAID, NPC_GENERATOR); + addSkillSeeId(NPC_GENERATOR); + addSpawnId(NPC_ATTACKER_GENERATORS, NPC_ATTACKER_GENERATORS_1, LYN_DRACO_ATTACKER_GENERATORS, GENERATOR_GUARD, NPC_GENERATOR); + addFirstTalkId(NPC_GENERATOR); + addSeeCreatureId(INVISIBLE); + _zoneLair = ZoneManager.getInstance().getZoneById(ZONE_ID, L2NoSummonFriendZone.class); + // Unlock + final StatsSet info = GrandBossManager.getInstance().getStatsSet(LINDVIOR_RAID); + final long time = info.getLong("respawn_time") - System.currentTimeMillis(); + if (time > 0) + { + startQuestTimer("unlock_lindvior", time, null, null); + } + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + // Anti BUGGERS + if (!_zoneLair.isInsideZone(attacker)) + { + attacker.doDie(null); + _log.warning(getName() + ": Character: " + attacker.getName() + " attacked: " + npc.getName() + " out of the boss zone!"); + } + if (!_zoneLair.isInsideZone(npc)) + { + npc.teleToLocation(CENTER_LOCATION, true); + _log.warning(getName() + ": Character: " + attacker.getName() + " attacked: " + npc.getName() + " wich is out of the boss zone!"); + } + + double percent = ((npc.getCurrentHp() - damage) / npc.getMaxHp()) * 100; + if ((percent <= 80) && (_status == 0)) + { + _zoneLair.broadcastPacket(new OnEventTrigger(RED_ZONE_EFFECT, true)); + _zoneLair.getPlayersInside().stream().forEach(p -> + { + startQuestTimer("stop_red_zone", 10000, _lindvior, p); + p.broadcastPacket(new ExShowScreenMessage(NpcStringId.A_FEARSOME_POWER_EMANATES_FROM_LINDVIOR, ExShowScreenMessage.TOP_CENTER, 2000, true)); + }); + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_FLY, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.8); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true); + addSpawn(LINDVIOR_SERVITOR[0], loc, true); + } + _status = 1; + } + else if ((percent <= 75) && (_status == 1)) + { + _bigVortexesTask = ThreadPoolManager.schedule(() -> spawnServitor(1, 300, _lindvior.getLocation(), NPC_ATTACKER_BIG_VORTEX), 1000); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(LINDVIOR_SERVITOR[1], loc, true); + } + _zoneLair.getPlayersInside().stream().forEach(p -> p.broadcastPacket(new ExShowScreenMessage(NpcStringId.A_GIGANTIC_WHIRLWIND_HAS_APPEARED, ExShowScreenMessage.TOP_CENTER, 2000, true))); + _status = 2; + } + else if ((percent <= 60) && (_status == 2)) + { + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_GROUND, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.6); + spawnServitor(10, 2000, _lindvior.getLocation(), LINDVIOR_SERVITOR); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(LINDVIOR_SERVITOR[2], loc, true); + } + _skillCastTask = ThreadPoolManager.scheduleAtFixedRate(() -> _lindvior.doCast(SKILL_REFLECT.getSkill()), 5000, 80000); + _status = 3; + } + else if ((percent <= 40) && (_status == 3)) + { + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_FLY, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.4); + + if (SpawnTable.getInstance().getSpawns(NPC_ATTACKER_BIG_VORTEX) != null) + { + if ((_vortex != null) && (_vortex.getId() == NPC_ATTACKER_SMALL_VORTEX)) + { + _vortex.getSpawn().stopRespawn(); + _vortex.deleteMe(); + } + } + _status = 4; + } + else if ((percent <= 35) && (_status == 4)) + { + _smallVortexesTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true, 60000); + addSpawn(LINDVIOR_SERVITOR[3], loc, true); + } + + }, 20000, 60000); + _status = 5; + } + else if ((percent <= 20) && (_status == 5)) + { + if (_smallVortexesTask != null) + { + _smallVortexesTask.cancel(true); + _smallVortexesTask = null; + } + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.LINDVIOR_HAS_LANDED, 2, 5000, true)); + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_RAID, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.2); + _bigVortexesTask = ThreadPoolManager.schedule(() -> spawnServitor(1, 300, _lindvior.getLocation(), NPC_ATTACKER_BIG_VORTEX), 1000); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true); + addSpawn(LINDVIOR_SERVITOR[4], loc, true); + addSpawn(LINDVIOR_SERVITOR[3], loc, true); + } + _collapseTask = ThreadPoolManager.schedule(Lindvior.this::Clean, 600000); + _status = 6; + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + protected void Clean() + { + _status = 0; + if (_socialTask != null) + { + _socialTask.cancel(false); + _socialTask = null; + } + if (_announceTask != null) + { + _announceTask.cancel(false); + _announceTask = null; + } + if (_announceProtect != null) + { + _announceProtect.cancel(false); + _announceProtect = null; + } + if (_skillCastTask != null) + { + _skillCastTask.cancel(false); + _skillCastTask = null; + } + if (_LynDracoTask != null) + { + _LynDracoTask.cancel(false); + _LynDracoTask = null; + } + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(false); + _mobsSpawnTask = null; + } + if (_collapseTask != null) + { + _collapseTask.cancel(false); + _collapseTask = null; + } + if (_bigVortexesTask != null) + { + _bigVortexesTask.cancel(false); + _bigVortexesTask = null; + } + if (_smallVortexesTask != null) + { + _smallVortexesTask.cancel(false); + _smallVortexesTask = null; + } + if (_lionel != null) + { + _lionel.deleteMe(); + } + _zoneLair.getCharactersInside().forEach(mob -> + { + if (mob.isNpc()) + { + mob.deleteMe(); + mob.setIsDead(true); + } + }); + } + + private void Fail(boolean clean) + { + if (clean) + { + Clean(); + } + _zoneLair.oustAllPlayers(); + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, false)); + cancelQuestTimers("attack_generator"); + if (GrandBossManager.getInstance().getBossStatus(LINDVIOR_RAID) != 3) + { + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, ALIVE); + } + } + + @Override + public synchronized String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon) + { + if ((skill.getId() == 15606) && (npc.getId() == NPC_GENERATOR)) + { + synchronized (_chargedValues) + { + int index = npc.getScriptValue(); + if (!hasFlag(_chargedMask, 1 << index)) + { + _chargedValues[index] += caster.isGM() ? (30 / 4) + 2 : (1 / 4) + 2; + _chargedValues[index] = Math.min(_chargedValues[index], 120); + + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 3000, player -> + { + player.sendPacket(new ExShowScreenMessage(NpcStringId.S1_HAS_CHARGED_THE_CANNON, ExShowScreenMessage.TOP_CENTER, 10000, true, caster.getName())); + player.sendPacket(new ExSendUIEvent(player, ExSendUIEvent.TYPE_NORNIL, _chargedValues[index], 120, NpcStringId.CHARGING)); + }); + if (_chargedValues[index] >= 120) + { + _chargedMask |= 1 << index; + _chargedValues[index] = 0; + } + + if (hasFlag(_chargedMask, 0xf)) + { + nextStage(3); + } + } + } + } + return null; + } + + @Override + public String onSpawn(L2Npc npc) + { + switch (npc.getId()) + { + case NPC_ATTACKER_GENERATORS: + case NPC_ATTACKER_GENERATORS_1: + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2GuardInstance.class, 800, cha -> + { + + if (cha.getId() == GENERATOR_GUARD) + { + npc.reduceCurrentHp(1, cha, null); + cha.reduceCurrentHp(1, npc, null); + } + if (cha.getId() == NPC_GENERATOR) + { + ((L2Attackable) npc).addDamageHate(cha, 500, 98); + } + }); + break; + } + case LYN_DRACO_ATTACKER_GENERATORS: + { + ((L2Attackable) npc).setCanStopAttackByTime(false); + ((L2Attackable) npc).setCanReturnToSpawnPoint(false); + startQuestTimer("attack_generator", 10000, npc, null, true); + break; + } + case GENERATOR_GUARD: + { + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + ((L2GuardInstance) npc).setIsInvul(true); + break; + } + case NPC_GENERATOR: + { + npc.disableCoreAI(true); + npc.setDisplayEffect(1); + npc.setRandomWalking(false); + npc.setIsInvul(true); // Can't get damage now + _activeMask = 0; + _chargedMask = 0; + break; + } + } + return super.onSpawn(npc); + } + + @Override + public String onSeeCreature(L2Npc npc, L2Character player, boolean isSummon) + { + setLindviorSpawnTask(); + npc.getSpawn().stopRespawn(); + npc.deleteMe(); + return super.onSeeCreature(npc, player, isSummon); + } + + private void nextStage(int _taskId) + { + switch (_taskId) + { + case 1: // Spawn Generators + { + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, true)); + int i = 0; + L2GuardInstance guard; + for (Location loc : CONTROL_GENERATOR_SPAWNS) + { + guard = (L2GuardInstance) addSpawn(NPC_GENERATOR, loc, true); + guard.setDisplayEffect(0x01); + guard.setScriptValue(i++); + _generatorSpawn.add(guard); + } + + L2Npc npc; + for (Location loc : SCHEME_GENERATOR_SPAWNS) + { + npc = addSpawn(GENERATOR_GUARD, loc, true); + npc.setRandomWalking(false); + _guardSpawn.add(npc); + } + + _mobsSpawnTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : ATTACKER_GENERATOR_SPAWNS) + { + if (getRandom(10) <= 5) + { + _monsterSpawn.add(addSpawn(NPC_ATTACKER_GENERATORS, loc, true)); + } + else + { + _monsterSpawn.add(addSpawn(NPC_ATTACKER_GENERATORS_1, loc, true)); + } + } + }, 30000, 80000); + + _dummyLindvior = addSpawn(LINDVIOR_CAMERA, 45259, -27115, -638, 41325, false, 0, false); + _announceTask = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(player -> player.sendPacket(new ExShowScreenMessage(NpcStringId.YOU_MUST_ACTIVATE_THE_4_GENERATORS, ExShowScreenMessage.TOP_CENTER, 7000, true))), 10000, 20000); + break; + } + case 2: // After activation of 4 generators, we wait to be charged + { + if (_announceTask != null) + { + _announceTask.cancel(true); + _announceTask = null; + } + _generatorSpawn.forEach(npc -> + { + npc.setDisplayEffect(1); + npc.setIsInvul(false); + npc.broadcastInfo(); + }); + + _zoneLair.getPlayersInside().forEach(player -> + { + player.sendPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, false)); + cancelQuestTimers("NPC_SHOUT"); + _guardSpawn.stream().forEach(guard -> + { + guard.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.ALL_4_GENERATORS_MUST_BE_ACTIVATED); + }); + _announceProtect = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(p -> player.sendPacket(new ExShowScreenMessage(NpcStringId.PROTECT_THE_GENERATOR, ExShowScreenMessage.TOP_CENTER, 7000, true))), 10000, 18000); + _zoneLair.broadcastPacket(new SpecialCamera(_dummyLindvior, 3300, 200, 20, 11000, 10500, 0, 8, 1, 0, 0)); + _generatorSpawn.forEach(npc -> npc.sendInfo(player)); + startQuestTimer("show_movie", 13000, null, null); + startQuestTimer("start_charge", 35000, null, null); + startQuestTimer("show_shield_animation", 2000, null, null); + }); + break; + } + case 3: // After charging all the generators + { + _zoneLair.broadcastPacket(new OnEventTrigger(ALL_GENERATORS_CONNECTED_EFFECT, true)); + if (_announceTask != null) + { + _announceTask.cancel(true); + _announceTask = null; + } + if (_announceProtect != null) + { + _announceProtect.cancel(false); + _announceProtect = null; + } + if (_skillCastTask != null) + { + _skillCastTask.cancel(true); + _skillCastTask = null; + } + if (_LynDracoTask != null) + { + _LynDracoTask.cancel(true); + _LynDracoTask = null; + } + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(true); + _mobsSpawnTask = null; + } + _monsterSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _LinDracoSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _generatorSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _guardSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + cancelQuestTimers("attack_generator"); + _lindvior2.setIsDead(true); + _lindvior2.deleteMe(); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, FIGHTING); + _lionel = addSpawn(LIONEL_HUNTER, 42630, -48231, -792, 855, false, 0, false); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_GROUND, CENTER_LOCATION, false, 0, true); + _zoneLair.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _zoneLair.getPlayersInside().forEach(_lindvior::sendInfo); + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.LINDVIOR_HAS_FALLEN_FROM_THE_SKY, ExShowScreenMessage.TOP_CENTER, 7000)); + _mobsSpawnTask = ThreadPoolManager.scheduleAtFixedRate(() -> spawnServitor(2, 1000, _lindvior.getLocation(), LINDVIOR_SERVITOR), 60000, 180000); + break; + } + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + switch (event) + { + case "unlock_lindvior": + { + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, ALIVE); + break; + } + case "stage_1_activate_generator": + { + int index = npc.getScriptValue(); + if (!hasFlag(_activeMask, 1 << index)) + { + _activeMask |= 1 << index; + npc.setDisplayEffect(0x02); + sendEventTrigger(true, GENERATOR_TRIGERS[index]); + _zoneLair.getPlayersInside().stream().forEach(p -> p.broadcastPacket(new Earthquake(p.getX(), p.getY(), p.getZ(), 20, 10))); + if (hasFlag(_activeMask, 0xf)) + { + nextStage(2); + } + } + break; + } + case "show_shield_animation": // zone brodcat shield event triger + { + _zoneLair.getPlayersInside().forEach(p -> + { + p.sendPacket(new OnEventTrigger(SECOND_STAGE_EVENT_TRIGGER, true)); + }); + _guardSpawn.stream().forEach(guard -> + { + guard.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.THE_GENERATOR_IS_CONNECTED_TO_THE_CANNON); + }); + break; + } + case "show_movie": // zone brodcat Lindvior scene movie + { + _zoneLair.getPlayersInside().forEach(p -> + { + playMovie(p, Movie.SC_LIND_OPENING); + }); + _dummyLindvior.deleteMe(); + _lindvior2 = addSpawn(LINDVIOR_FAKE, CENTER_LOCATION, false, 0, false); + _lindvior2.setTargetable(false); + _announceTask = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(p -> p.sendPacket(new ExShowScreenMessage(NpcStringId.CHARGE_THE_CANNON_USING_THE_GENERATOR, ExShowScreenMessage.TOP_CENTER, 7000, true))), 40000, 20000); + break; + } + case "start_charge": + { + _skillCastTask = ThreadPoolManager.scheduleAtFixedRate(() -> _generatorSpawn.forEach(generators -> + { + int index = generators.getScriptValue(); + if (!generators.isCastingNow() && (generators.getEffectList().getBuffInfoBySkillId(SKILL_RECHARGE_POSIBLE.getSkillId()) == null) && !hasFlag(_chargedMask, 1 << index)) + { + // TODO Need core implemented combo skill packet. + // On this moment player automatic charge generator if distance generator and player <= 900 + generators.doCast(SKILL_RECHARGE_POSIBLE.getSkill()); + L2World.getInstance().forEachVisibleObjectInRange(generators, L2PcInstance.class, 900, p -> + { + p.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + p.setTarget(generators); + p.doCast(RECHARGE.getSkill()); + }); + _guardSpawn.stream().forEach(guard -> + { + guard.setTarget(generators); + guard.doCast(RECHARGE.getSkill()); + guard.setIsInvul(false); + if (!guard.isDead()) + { + guard.broadcastSay(ChatType.NPC_GENERAL, GUARD_MSG_1[getRandom(GUARD_MSG_1.length)]); + } + }); + } + }), 10000, 20000); + _LynDracoTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : LYN_DRACO_SPAWNS) + { + _LinDracoSpawn.add(addSpawn(LYN_DRACO_ATTACKER_GENERATORS, loc, true)); + } + }, 20000, 60000); + break; + } + case "stop_red_zone": + { + _zoneLair.broadcastPacket(new OnEventTrigger(RED_ZONE_EFFECT, false)); + break; + } + case "attack_generator": + { + if ((npc != null) && !npc.isDead()) + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2GuardInstance.class, 3000, generator -> + { + if (generator.getId() == NPC_GENERATOR) + { + npc.setTarget(generator); + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, generator.getLocation()); + if (npc.distFromMe(generator) < 500) + { + npc.reduceCurrentHp(1, generator, null); + generator.reduceCurrentHp(1, npc, null); + } + } + }); + } + break; + } + } + return null; + } + + @Override + public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon) + { + if (npc.getId() == LINDVIOR_RAID) + { + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.HONORABLE_WARRIORS_HAVE_DRIVEN_OFF_LINDVIOR_THE_EVIL_WIND_DRAGON, ExShowScreenMessage.TOP_CENTER, 10000, true)); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, DEAD); + final long respawnTime = (Config.LINDVIOR_SPAWN_INTERVAL + getRandom(-Config.LINDVIOR_SPAWN_RANDOM, Config.LINDVIOR_SPAWN_RANDOM)) * 3600000; + final StatsSet info = GrandBossManager.getInstance().getStatsSet(LINDVIOR_RAID); + info.set("respawn_time", System.currentTimeMillis() + respawnTime); + GrandBossManager.getInstance().setStatsSet(LINDVIOR_RAID, info); + startQuestTimer("unlock_lindvior", respawnTime, null, null); + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(true); + _mobsSpawnTask = null; + } + _zoneLair.getCharactersInside().stream().filter(L2Character::isNpc).forEach(mob -> mob.deleteMe()); + ThreadPoolManager.schedule(() -> npc.decayMe(), 10000); + _zoneLair.broadcastPacket(new OnEventTrigger(SECOND_STAGE_EVENT_TRIGGER, false)); + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, true)); + _lionel.deleteMe(); + } + else if (npc.getId() == NPC_GENERATOR) + { + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.THE_GENERATOR_HAS_BEEN_DESTROYED, ExShowScreenMessage.TOP_CENTER, 5000, true)); + Clean(); + _collapseTask = ThreadPoolManager.schedule(() -> Fail(false), 20000); + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onFirstTalk(L2Npc npc, L2PcInstance player) + { + if (npc.getId() == NPC_GENERATOR) + { + return npc.getDisplayEffect() == 1 ? "19477.html" : "19477-01.html"; + } + return super.onFirstTalk(npc, player); + } + + @Override + public String onEnterZone(L2Character character, L2ZoneType zone) + { + if (zone.getId() == ZONE_ID) + { + if (_collapseTask != null) + { + _collapseTask.cancel(true); + _collapseTask = null; + } + } + return super.onEnterZone(character, zone); + } + + @Override + public String onExitZone(L2Character character, L2ZoneType zone) + { + if (zone.getId() == ZONE_ID) + { + if (zone.getPlayersInside().isEmpty()) + { + _collapseTask = ThreadPoolManager.schedule(() -> Fail(true), 900000); + } + } + return super.onExitZone(character, zone); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + if (event.equals("NPC_SHOUT")) + { + if ((npc != null) && !npc.isDead()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, GUARD_MSG[getRandom(GUARD_MSG.length)]); + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + } + } + } + + private void sendEventTrigger(boolean status, int... triggers) + { + IClientOutgoingPacket[] pakets = new IClientOutgoingPacket[triggers.length]; + for (int i = 0; i < triggers.length; i++) + { + pakets[i] = new OnEventTrigger(triggers[i], status); + } + for (IClientOutgoingPacket packet : pakets) + { + _zoneLair.broadcastPacket(packet); + } + } + + private void spawnServitor(int count, int radius, Location loc, int... npcIds) + { + int x = loc.getX(), y = loc.getY(); + if (radius > 0) + { + x += Rnd.get(-radius, radius); + y += Rnd.get(-radius, radius); + } + + for (int i = 0; i < count; i++) + { + _monsterSpawn.add(addSpawn(npcIds[getRandom(npcIds.length)], x, y, loc.getZ(), loc.getHeading(), true, 0, true)); + } + } + + private static boolean hasFlag(int val, int flag) + { + return (val & flag) == flag; + } + + public void setLindviorSpawnTask() + { + synchronized (this) + { + if (_socialTask == null) + { + _socialTask = ThreadPoolManager.schedule(() -> nextStage(1), 3000); + } + } + } + + @RegisterEvent(EventType.ON_CREATURE_DAMAGE_RECEIVED) + @RegisterType(ListenerRegisterType.NPC) + @Id(LINDVIOR_FLY) + @Id(LINDVIOR_RAID) + @Id(LINDVIOR_GROUND) + public void onCreatureDamageReceived(OnCreatureDamageReceived event) + { + _zoneLair.getPlayersInside().stream().forEach(p -> + { + switch (_status) + { + case 0: + case 1: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 1, -1, 0.015, true); + break; + } + case 2: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 2, -1, 0.015, true); + break; + } + case 3: + case 4: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 3, -1, 0.015, true); + break; + } + case 5: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 4, -1, 0.015, true); + break; + } + } + }); + } + + public static void main(String[] args) + { + new Lindvior(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java new file mode 100644 index 0000000000..d60c088f9f --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java @@ -0,0 +1,175 @@ +/* + * 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 ai.bosses.Lindvior; + +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.SkillHolder; + +import ai.AbstractNpcAI; + +/** + * LindviorBoss AI + * @author Gigi + * @date 2017-08-02 - [11:05:21] + */ +public class LindviorBoss extends AbstractNpcAI +{ + // Boss + private static final int LINDVIOR_GROUND = 25899; + private static final int LINDVIOR_RAID = 29240; + private static final int LINDVIOR_FLY = 19424; + // Skills + private static final SkillHolder SKILL_FLY_UP = new SkillHolder(15278, 1); + private static final SkillHolder SKILL_RABIES = new SkillHolder(15269, 1); + private static final SkillHolder SKILL_FLY = new SkillHolder(15279, 1); + private static final SkillHolder MASS_HELL_BINDING = new SkillHolder(11052, 6); + private static final SkillHolder MIGHTY_WIND_STRIKE = new SkillHolder(15274, 1); + private static final SkillHolder WIND_PULL = new SkillHolder(15591, 1); + private static final SkillHolder LINDVIORS_JUMP = new SkillHolder(15430, 1); + private static final SkillHolder BODY_SLAM = new SkillHolder(15271, 1); + private static final SkillHolder SOAR = new SkillHolder(15279, 1); + private static final SkillHolder WIND_BREAT = new SkillHolder(15272, 1); + private static final SkillHolder TAIL_SWIPE = new SkillHolder(15273, 1); + private static final SkillHolder TORNADO = new SkillHolder(15275, 1); + private static final SkillHolder LINDVIORS_ATTACK = new SkillHolder(15600, 1); + // Chances + private final static int CHANCE_MIGHTY_WIND_STRIKE = 9; + private final static int CHANCE_WIND_PULL = 4; + private final static int CHANCE_LINDVIORS_JUMP = 7; + private final static int CHANCE_BODY_SLAM = 2; + private final static int CHANCE_SOAR = 8; + private final static int CHANCE_WIND_BREAT = 3; + private final static int CHANCE_TAIL_SWIPE = 5; + private final static int CHANCE_TORNADO = 6; + private final static int CHANCE_LINDVIORS_ATTACK = 1; + + public LindviorBoss() + { + super(); + addAttackId(LINDVIOR_GROUND, LINDVIOR_FLY, LINDVIOR_RAID); + addSpawnId(LINDVIOR_FLY); + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + double percent = ((npc.getCurrentHp() - damage) / npc.getMaxHp()) * 100; + final int chance = getRandom(100); + switch (npc.getId()) + { + case LINDVIOR_GROUND: + { + if ((percent <= 80) && npc.isScriptValue(0)) + { + + npc.doCast(SKILL_FLY_UP.getSkill()); + npc.doCast(SKILL_RABIES.getSkill()); + npc.setScriptValue(1); + } + else if ((percent <= 40) && (npc.isScriptValue(1))) + { + npc.doCast(SKILL_FLY.getSkill()); + npc.setScriptValue(2); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_MIGHTY_WIND_STRIKE)) + { + npc.setTarget(attacker); + npc.doCast(MIGHTY_WIND_STRIKE.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_PULL)) + { + npc.setTarget(attacker); + npc.doCast(WIND_PULL.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_LINDVIORS_JUMP)) + { + npc.setTarget(attacker); + npc.doCast(LINDVIORS_JUMP.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_BODY_SLAM)) + { + npc.setTarget(attacker); + npc.doCast(BODY_SLAM.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TAIL_SWIPE)) + { + npc.setTarget(attacker); + npc.doCast(TAIL_SWIPE.getSkill()); + } + break; + } + case LINDVIOR_FLY: + { + if (!npc.isCastingNow() && (chance <= CHANCE_SOAR)) + { + npc.setTarget(attacker); + npc.doCast(SOAR.getSkill()); + } + break; + } + case LINDVIOR_RAID: + { + if ((percent <= 20) && (npc.isScriptValue(0))) + { + npc.doCast(SKILL_FLY.getSkill()); + npc.setScriptValue(1); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_BREAT)) + { + npc.setTarget(attacker); + npc.doCast(WIND_BREAT.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_PULL)) + { + npc.setTarget(attacker); + npc.doCast(WIND_PULL.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TAIL_SWIPE)) + { + npc.setTarget(attacker); + npc.doCast(TAIL_SWIPE.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TORNADO)) + { + npc.setTarget(attacker); + npc.doCast(TORNADO.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_LINDVIORS_ATTACK)) + { + npc.setTarget(attacker); + npc.doCast(LINDVIORS_ATTACK.getSkill()); + } + break; + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + npc.setRandomWalking(true); + npc.doCast(MASS_HELL_BINDING.getSkill()); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new LindviorBoss(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java new file mode 100644 index 0000000000..846ada3442 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java @@ -0,0 +1,67 @@ +/* + * 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 ai.bosses.Lindvior; + +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.instancemanager.WalkingManager; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.NpcStringId; + +import ai.AbstractNpcAI; + +/** + * Lionel Hunter AI + * @author Gigi + * @date 2017-07-23 - [22:54:59] + */ +public class LionelHunter extends AbstractNpcAI +{ + // Npc + private static final int LIONEL_HUNTER = 33886; + // Misc + private static final String ROUTE_NAME = "Rune_Lionel"; + + public LionelHunter() + { + addSpawnId(LIONEL_HUNTER); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + if (event.equals("NPC_SHOUT") && (npc != null)) + { + npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.WE_JUST_LOCATED_LINDVIOR_THOSE_WHO_ARE_WILLING_TO_FIGHT_CAN_DO_SO_AT_ANY_TIME_NOW); + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + } + } + + @Override + public String onSpawn(L2Npc npc) + { + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + WalkingManager.getInstance().startMoving(npc, ROUTE_NAME); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new LionelHunter(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java new file mode 100644 index 0000000000..d9bf024d24 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java @@ -0,0 +1,176 @@ +/* + * 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 ai.bosses.Lindvior; + +import java.util.Collection; + +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.serverpackets.FlyToLocation; +import com.l2jmobius.gameserver.network.serverpackets.ValidateLocation; + +import ai.AbstractNpcAI; + +/** + * Vortex AI + * @author Gigi + * @date 2017-07-23 - [10:32:50] + */ +public class Vortex extends AbstractNpcAI +{ + private static final int SMALL_VORTEX = 25898; + private static final int BIG_VORTEX = 19427; + + public Vortex() + { + super(); + addSeeCreatureId(SMALL_VORTEX, BIG_VORTEX); + addSpawnId(SMALL_VORTEX, BIG_VORTEX); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + switch (event) + { + case "rnd_small": + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 250, attackers -> + { + if ((attackers != null) && !attackers.isDead() && !attackers.isAlikeDead()) + { + attackers.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + final int radians = (int) Math.toRadians(npc.calculateDirectionTo(attackers)); + final int x = (int) (attackers.getX() + (600 * Math.cos(radians))); + final int y = (int) (attackers.getY() + (600 * Math.sin(radians))); + final int z = attackers.getZ(); + final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld()); + attackers.broadcastPacket(new FlyToLocation(attackers, x, y, z, FlyToLocation.FlyType.THROW_UP, 800, 800, 800)); + attackers.setXYZ(loc); + attackers.broadcastPacket(new ValidateLocation(attackers)); + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player); + startQuestTimer("stop_knock_down", 5000, npc, attackers); + startQuestTimer("despawn_small", 5000, npc, null); + } + }); + break; + } + case "rnd_big": + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 500, attackers -> + { + if ((attackers != null) && !attackers.isDead() && !attackers.isAlikeDead()) + { + attackers.setCurrentHp(1.0); + attackers.setCurrentMp(1.0); + attackers.setCurrentCp(1.0); + startQuestTimer("despawn_big", 600000, npc, null); + } + }); + break; + } + case "despawn_small": + { + if (npc != null) + { + cancelQuestTimers("rnd_small"); + npc.getSpawn().stopRespawn(); + npc.doDie(null); + } + break; + } + case "despawn_big": + { + if (npc != null) + { + cancelQuestTimers("despawn_big"); + npc.getSpawn().stopRespawn(); + npc.deleteMe(); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSeeCreature(L2Npc npc, L2Character player, boolean isSummon) + { + switch (npc.getId()) + { + case SMALL_VORTEX: + { + startQuestTimer("rnd_small", 5000, npc, null, true); + break; + } + case BIG_VORTEX: + { + startQuestTimer("rnd_big", 10000, npc, null, true); + break; + } + } + return super.onSeeCreature(npc, player, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + switch (npc.getId()) + { + case SMALL_VORTEX: + { + attackRandomTarget(npc); + npc.setRandomWalking(true); + npc.setIsRunning(true); + break; + } + case BIG_VORTEX: + { + attackRandomTarget(npc); + npc.setRandomWalking(true); + npc.setIsRunning(true); + break; + } + } + return super.onSpawn(npc); + } + + private void attackRandomTarget(L2Npc npc) + { + final Collection players = L2World.getInstance().getVisibleObjects(npc, L2PcInstance.class); + { + if ((players == null) || players.isEmpty()) + { + return; + } + if (players.size() > 0) + { + addAttackPlayerDesire(npc, players.stream().findAny().get()); + } + } + } + + public static void main(String[] args) + { + new Vortex(); + } +} diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/08500-08599.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/08500-08599.xml index 75fd3434dd..5799fc23b8 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/08500-08599.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/08500-08599.xml @@ -1954,7 +1954,7 @@ - + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19400-19499.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19400-19499.xml index c55d343d88..ae0149fcf5 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19400-19499.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19400-19499.xml @@ -825,58 +825,76 @@ - + DRAGON FEMALE - - - + + - + - - + + - + + - - + - - + + + + + + + + + + - + DRAGON FEMALE - - - + + - + - - + + - + + - - + - - - + + + + + + + + + + + + + + + @@ -984,7 +1002,7 @@ - + @@ -2357,7 +2375,7 @@ - + ETC FEMALE @@ -2373,7 +2391,10 @@ - + + + + @@ -2401,7 +2422,7 @@ - + ETC FEMALE @@ -2412,7 +2433,7 @@ - + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/25800-25899.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/25800-25899.xml index 699514cf2e..48950deb04 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/25800-25899.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/25800-25899.xml @@ -4800,7 +4800,7 @@ - + DRAGON FEMALE @@ -4810,8 +4810,8 @@ - - + + @@ -4831,7 +4831,7 @@ - + DRAGON FEMALE @@ -4862,7 +4862,7 @@ - + DRAGON FEMALE @@ -4886,6 +4886,12 @@ + + + + + + @@ -4893,15 +4899,18 @@ - + + + + DRAGON FEMALE - - + + @@ -4919,29 +4928,29 @@ - + true + - - + DRAGON FEMALE - - + + + - - + + - - + + - @@ -4950,11 +4959,16 @@ + + + + + - - + + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/29200-29299.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/29200-29299.xml index da4bfc1ef0..9c4612664c 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/29200-29299.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/29200-29299.xml @@ -2046,13 +2046,13 @@ - - + DRAGON FEMALE + - + @@ -2066,91 +2066,123 @@ - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2163,7 +2195,7 @@ - + DRAGON FEMALE diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/skills/15600-15699.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/skills/15600-15699.xml index 2e0705da15..c7d1a933ea 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/stats/skills/15600-15699.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/skills/15600-15699.xml @@ -49,23 +49,38 @@ 2 1800 - - + icon.skill0005 + 20 A2 + 1000 + 1000 1 - 25000 + 10000 + SELF + RANGE + NOT_FRIEND - icon.skill1449 + icon.skill14444 A1 + 1 900 10000 -2 - 200 + 200 + TARGET + SINGLE + + + + 19477 + + + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/zones/no_summon_friend.xml b/L2J_Mobius_2.5_Underground/dist/game/data/zones/no_summon_friend.xml index a6b09689a0..7b5203b963 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/zones/no_summon_friend.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/zones/no_summon_friend.xml @@ -167,4 +167,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java index b0a99b5244..3bd48421fc 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java @@ -893,6 +893,13 @@ public final class Config public static int KELBIM_SPAWN_INTERVAL; public static int KELBIM_SPAWN_RANDOM; + // Lindvior + public static int LINDVIOR_SPAWN_INTERVAL; + public static int LINDVIOR_SPAWN_RANDOM; + public static int LINDVIOR_MIN_PLAYERS; + public static int LINDVIOR_MAX_PLAYERS; + public static int LINDVIOR_MIN_PLAYER_LVL; + // Anakim public static int ANAKIM_MIN_PLAYERS; public static int ANAKIM_MAX_PLAYERS; @@ -2227,6 +2234,11 @@ public final class Config LILITH_SPAWN_RANDOM = GrandBossSettings.getInt("RandomOfLilithSpawn", 148); LILITH_MIN_PLAYER_LVL = GrandBossSettings.getInt("LilithMinPlayerLvl", 85); LILITH_MAX_PLAYER_LVL = GrandBossSettings.getInt("LilithMaxPlayerLvl", 89); + LINDVIOR_SPAWN_INTERVAL = GrandBossSettings.getInt("IntervalOfLindviorSpawn", 264); + LINDVIOR_SPAWN_RANDOM = GrandBossSettings.getInt("RandomOfLindviorSpawn", 72); + LINDVIOR_MIN_PLAYERS = GrandBossSettings.getInt("LindviorMinPlayers", 49); + LINDVIOR_MAX_PLAYERS = GrandBossSettings.getInt("LindviorMaxPlayers", 112); + LINDVIOR_MIN_PLAYER_LVL = GrandBossSettings.getInt("LindviorMinPlayerLvl", 99); // Gracia Seeds final PropertiesParser GraciaSeedsSettings = new PropertiesParser(GRACIASEEDS_CONFIG_FILE); diff --git a/L2J_Mobius_2.5_Underground/readme.txt b/L2J_Mobius_2.5_Underground/readme.txt index d1719fb4a5..38ebed6388 100644 --- a/L2J_Mobius_2.5_Underground/readme.txt +++ b/L2J_Mobius_2.5_Underground/readme.txt @@ -19,7 +19,6 @@ What is done -Addition of many retail AIs TODO list --Lindvior -Trasken -Underground five man dungeons -Kamaloka diff --git a/L2J_Mobius_3.0_Helios/dist/db_installer/sql/game/grandboss_data.sql b/L2J_Mobius_3.0_Helios/dist/db_installer/sql/game/grandboss_data.sql index 27ff367d22..68a2deaa1e 100644 --- a/L2J_Mobius_3.0_Helios/dist/db_installer/sql/game/grandboss_data.sql +++ b/L2J_Mobius_3.0_Helios/dist/db_installer/sql/game/grandboss_data.sql @@ -17,9 +17,10 @@ INSERT IGNORE INTO `grandboss_data` (`boss_id`,`loc_x`,`loc_y`,`loc_z`,`heading` (29006, 17726, 108915, -6480, 0, 622493.58388, 3793.536), -- Core (29014, 55024, 17368, -5412, 10126, 622493.58388, 3793.536), -- Orfen (29020, 116033, 17447, 10107, -25348, 4068372, 39960), -- Baium -(29028, -105200, -253104, -15264, 0, 62041918, 2248572), -- Valakas (29068, 185708, 114298, -8221,32768, 62802301, 1998000), -- Antharas +(29028, -105200, -253104, -15264, 0, 62041918, 2248572), -- Valakas +(29240, 0, 0, 0, 0, 288282589, 47100), -- Lindvior (29118, 0, 0, 0, 0, 4109288, 1220547), -- Beleth (25286, 185080, -12613, -5499, 16550, 556345880, 86847), -- Anakim (25283, 185062, -9605, -5499, 15640, 486021997, 79600), -- Lilith -(26124, 0, 0, 0, 0, 13945521, 50920); -- Kelbim \ No newline at end of file +(26124, 0, 0, 0, 0, 13945521, 50920); -- Kelbim diff --git a/L2J_Mobius_3.0_Helios/dist/game/config/GrandBoss.ini b/L2J_Mobius_3.0_Helios/dist/game/config/GrandBoss.ini index 21b6037556..3689173278 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/config/GrandBoss.ini +++ b/L2J_Mobius_3.0_Helios/dist/game/config/GrandBoss.ini @@ -144,4 +144,23 @@ LilithMaxPlayers = 120 LilithMinPlayerLvl = 85 # Maximum players Level for enter to Lilith. Retail: 89 -LilithMaxPlayerLvl = 89 \ No newline at end of file +LilithMaxPlayerLvl = 89 + +# --------------------------------------------------------------------------- +# Lindvior +# --------------------------------------------------------------------------- + +# Interval time of Lindvior. Value is hour. Range 1-480. Retail: 264 +IntervalOfLindviorSpawn = 264 + +# Random interval. Range 1-192. Retail: 72 +RandomOfLindviorSpawn = 72 + +# Minimal count of players for enter to Lindvior. Retail: 49 +LindviorMinPlayers = 49 + +# Maximum count of players for enter to Lindvior. Retail: 112 +LindviorMaxPlayers = 112 + +# Minimum players Level for enter to Lindvior. Retail: 99 +LindviorMinPlayerLvl = 99 \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml index 5cbbf5261f..dc0e5372c2 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml @@ -2352,4 +2352,8 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java index 790799b0ad..b1a37e194f 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Rune/AltarOfSacrifice/AltarOfSacrifice.java @@ -75,7 +75,7 @@ public class AltarOfSacrifice extends AbstractNpcAI @Override public String onSeeCreature(L2Npc npc, L2Character creature, boolean isSummon) { - if (creature.isPlayer() && _jenas_guard.isScriptValue(0)) + if ((creature != null) && creature.isPlayer() && _jenas_guard.isScriptValue(0)) { startQuestTimer("msg_text", 3000, npc, null); _jenas_guard.setScriptValue(1); diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html new file mode 100644 index 0000000000..5f9fc4431e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477-01.html @@ -0,0 +1,3 @@ +Generator:
+The generator is now supplying power to the sealed structure. + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477.html new file mode 100644 index 0000000000..540ff6ac54 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/19477.html @@ -0,0 +1,3 @@ +Generator:

+ + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html new file mode 100644 index 0000000000..ba01eab970 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-1.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+On the Lindvior there is an attack!
+At this time it's impossible to enter the altar. + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html new file mode 100644 index 0000000000..e3eac44ec7 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-2.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+Lindvior? You're too late, friend.
+A group of warriors drove him off not long ago. + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html new file mode 100644 index 0000000000..40de9b961e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-3.html @@ -0,0 +1,4 @@ +Rune Castle Patrol Kato:
+You are overcome by a voice, a voice so powerful you are helpless as it speaks:
+(The players who belong to an association can only enter through the Association Leader.) + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html new file mode 100644 index 0000000000..9af5ff8c7a --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-4.html @@ -0,0 +1,3 @@ +Rune Castle Patrol Kato:
+(A command channel needs at least minimu: %min% and maximum: %max% members to challenge Lindvior.) + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html new file mode 100644 index 0000000000..309c938f02 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881-5.html @@ -0,0 +1,3 @@ +Rune Castle Patrol Kato:
+(A command channel members level must be minimum: %minlvl% Lvl or higher to challenge Lindvior.) + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html new file mode 100644 index 0000000000..bddff0b348 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/33881.html @@ -0,0 +1,6 @@ +Rune Castle Patrol Kato:
+Dire times dictated that I come myself from Rune Castle to help those in need here.
+What do you need?
+ + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java new file mode 100644 index 0000000000..3b54f9dfa8 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/KatoSicanus/KatoSicanus.java @@ -0,0 +1,129 @@ +/* + * 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 ai.bosses.Lindvior.KatoSicanus; + +import java.util.List; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.instancemanager.GrandBossManager; +import com.l2jmobius.gameserver.model.L2Party; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; + +import ai.AbstractNpcAI; + +/** + * Kato Sicanus Teleporter AI + * @author Gigi + * @date 2017-07-13 - [22:17:16] + */ +public class KatoSicanus extends AbstractNpcAI +{ + // NPCs + private static final int KATO_SICANUS = 33881; + private static final int LINDVIOR_RAID = 29240; + private static final int INVISIBLE = 8572; + // Location + private static final Location LINDVIOR_LOCATION = new Location(46929, -28807, -1400); + + public KatoSicanus() + { + addFirstTalkId(KATO_SICANUS); + addTalkId(KATO_SICANUS); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.equals("teleport")) + { + final int status = GrandBossManager.getInstance().getBossStatus(LINDVIOR_RAID); + if (player.isGM()) + { + player.teleToLocation(LINDVIOR_LOCATION, true); + addSpawn(INVISIBLE, 46707, -28586, -1400, 0, false, 60000, false); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, 1); + } + else + { + if (status == 2) + { + return "33881-1.html"; + } + if (status == 3) + { + return "33881-2.html"; + } + if (!player.isInParty()) + { + return "33881-3.html"; + } + final L2Party party = player.getParty(); + final boolean isInCC = party.isInCommandChannel(); + final List members = (isInCC) ? party.getCommandChannel().getMembers() : party.getMembers(); + final boolean isPartyLeader = (isInCC) ? party.getCommandChannel().isLeader(player) : party.isLeader(player); + if (!isPartyLeader) + { + return "33881-3.html"; + } + if ((members.size() < Config.LINDVIOR_MIN_PLAYERS) || (members.size() > Config.LINDVIOR_MAX_PLAYERS)) + { + final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId()); + packet.setHtml(getHtm(player.getHtmlPrefix(), "33881-4.html")); + packet.replace("%min%", Integer.toString(Config.LINDVIOR_MIN_PLAYERS)); + packet.replace("%max%", Integer.toString(Config.LINDVIOR_MAX_PLAYERS)); + player.sendPacket(packet); + return null; + } + for (L2PcInstance member : members) + { + if (member.getLevel() < Config.LINDVIOR_MIN_PLAYER_LVL) + { + final NpcHtmlMessage packet = new NpcHtmlMessage(npc.getObjectId()); + packet.setHtml(getHtm(player.getHtmlPrefix(), "33881-5.html")); + packet.replace("%minlvl%", Integer.toString(Config.LINDVIOR_MIN_PLAYER_LVL)); + player.sendPacket(packet); + return null; + } + } + for (L2PcInstance member : members) + { + if (member.isInsideRadius(npc, 1500, true, false)) + { + member.teleToLocation(LINDVIOR_LOCATION, true); + addSpawn(INVISIBLE, 46707, -28586, -1400, 0, false, 0, false); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, 1); + } + } + } + } + return null; + } + + @Override + public String onFirstTalk(L2Npc npc, L2PcInstance player) + { + return "33881.html"; + } + + public static void main(String[] args) + { + new KatoSicanus(); + } +} diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java new file mode 100644 index 0000000000..d6247a96c6 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Lindvior.java @@ -0,0 +1,976 @@ +/* + * 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 ai.bosses.Lindvior; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledFuture; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.enums.Movie; +import com.l2jmobius.gameserver.instancemanager.GrandBossManager; +import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance; +import com.l2jmobius.gameserver.model.actor.instance.L2GuardInstance; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.events.EventType; +import com.l2jmobius.gameserver.model.events.ListenerRegisterType; +import com.l2jmobius.gameserver.model.events.annotations.Id; +import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent; +import com.l2jmobius.gameserver.model.events.annotations.RegisterType; +import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureDamageReceived; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.Skill; +import com.l2jmobius.gameserver.model.zone.L2ZoneType; +import com.l2jmobius.gameserver.model.zone.type.L2NoSummonFriendZone; +import com.l2jmobius.gameserver.network.NpcStringId; +import com.l2jmobius.gameserver.network.serverpackets.Earthquake; +import com.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import com.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; +import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; +import com.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; +import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SpecialCamera; + +import ai.AbstractNpcAI; + +/** + * Lindvior Boss + * @author Gigi + * @date 2017-07-11 - [17:42:53] + *

+ * @VIDEO - https://www.youtube.com/watch?v=VknjOjRO9Cw + */ +public class Lindvior extends AbstractNpcAI +{ + // Monsters + private static final int LINDVIOR_FAKE = 19423; + private static final int LINDVIOR_GROUND = 25899; + private static final int LINDVIOR_RAID = 29240; + private static final int LINDVIOR_FLY = 19424; + private static final int NPC_GENERATOR = 19477; + private static final int GENERATOR_GUARD = 19479; + private static final int NPC_ATTACKER_GENERATORS = 25897; + private static final int NPC_ATTACKER_GENERATORS_1 = 25895; + private static final int LYN_DRACO_ATTACKER_GENERATORS = 29241; + private static final int NPC_ATTACKER_SMALL_VORTEX = 25898; + private static final int NPC_ATTACKER_BIG_VORTEX = 19427; + private static final int INVISIBLE = 8572; + private static final int LIONEL_HUNTER = 33886; + private static final int LINDVIOR_CAMERA = 19428; + // Zone + private final static int ZONE_ID = 12107; + static final Location CENTER_LOCATION = new Location(46424, -26200, -1400); + // Skills + private static final SkillHolder SKILL_RECHARGE_POSIBLE = new SkillHolder(15605, 1); + private static final SkillHolder RECHARGE = new SkillHolder(15606, 1); + private static final SkillHolder SKILL_REFLECT = new SkillHolder(15592, 1); + // Item + private static final int LINDVIORS_SCALE = 37495; + // Trigers + private static final int FIRST_STAGE_EVENT_TRIGGER = 21170112; + private static final int SECOND_STAGE_EVENT_TRIGGER = 21170100; + private static final int ALL_GENERATORS_CONNECTED_EFFECT = 21170110; + private static final int RED_ZONE_EFFECT = 21170120; + // Status + private static final int ALIVE = 0; + private static final int FIGHTING = 2; + private static final int DEAD = 3; + // Tasks + protected ScheduledFuture _socialTask; + protected ScheduledFuture _mobsSpawnTask; + protected ScheduledFuture _collapseTask; + protected ScheduledFuture _announceTask; + protected ScheduledFuture _announceProtect; + protected ScheduledFuture _skillCastTask; + protected ScheduledFuture _LynDracoTask; + protected ScheduledFuture _smallVortexesTask; + protected ScheduledFuture _bigVortexesTask; + protected L2NoSummonFriendZone _zoneLair; + protected L2GrandBossInstance _lindvior = null; + protected L2Npc _lindvior2 = null; + protected L2Npc _dummyLindvior; + protected L2Npc _vortex = null; + protected L2Npc _lionel = null; + protected List _guardSpawn = new ArrayList<>(); + protected List _generatorSpawn = new ArrayList<>(); + protected List _monsterSpawn = new ArrayList<>(); + protected List _LinDracoSpawn = new ArrayList<>(); + protected int _activeMask = 0; + protected int _chargedMask = 0; + protected int _status = 0; + + private static final Location[] CONTROL_GENERATOR_SPAWNS = + { + new Location(45288, -30360, -1432, 0), + new Location(48486, -27175, -1432, 0), + new Location(45272, -23976, -1432, 0), + new Location(42088, -27160, -1432, 0) + }; + private static final Location[] SCHEME_GENERATOR_SPAWNS = + { + new Location(48440, -26824, -1438, 0), + new Location(48392, -27448, -1438, 0), + new Location(42136, -27480, -1438, 0), + new Location(42136, -26840, -1438, 0), + new Location(44936, -24024, -1438, 0), + new Location(45592, -24008, -1438, 0), + new Location(45608, -30312, -1438, 0), + new Location(44984, -30360, -1438, 0) + }; + private static final Location[] ATTACKER_GENERATOR_SPAWNS = + { + new Location(44863, -24272, -1413, 33713), + new Location(45675, -24272, -1413, 33713), + new Location(45675, -30057, -1413, 64987), + new Location(44863, -30057, -1413, 64987), + new Location(42350, -27563, -1413, 46871), + new Location(42350, -26809, -1413, 46871), + new Location(48220, -26809, -1413, 16383), + new Location(48220, -27563, -1413, 16383) + }; + private static final Location[] LYN_DRACO_SPAWNS = + { + new Location(45300, -28402, -1400, 48845), + new Location(46379, -27178, -1400, 1154), + new Location(45292, -26043, -1400, 13027), + new Location(44215, -27172, -1400, 33966) + }; + private static final Location[] ATTACKER_SMALL_VORTEX_SPAWNS = new Location[] + { + new Location(46256, -30159, -1430, 57430), + new Location(45155, -29987, -1430, 14860), + new Location(46219, -27704, -1430, 1744), + new Location(46135, -28995, -1430, 43626), + new Location(43973, -28265, -1430, 16516), + new Location(46782, -29065, -1430, 63368), + new Location(47214, -29836, -1430, 46966), + new Location(44754, -29120, -1430, 56118), + new Location(47089, -28198, -1430, 8537), + new Location(44992, -28152, -1430, 11592), + new Location(44737, -24885, -1430, 3146), + new Location(46096, -24976, -1430, 49650), + new Location(46972, -25911, -1430, 62925), + new Location(46977, -27136, -1430, 2150), + new Location(42889, -24767, -1430, 10246), + new Location(47299, -25256, -1430, 1453), + new Location(44204, -25026, -1430, 39225), + new Location(42875, -28035, -1430, 34755), + new Location(41963, -26031, -1430, 18822), + new Location(43171, -25942, -1430, 44279), + new Location(41874, -27174, -1430, 56030), + new Location(44983, -26082, -1430, 7042), + new Location(46145, -26804, -1430, 24394), + new Location(46148, -26019, -1430, 34151), + new Location(45161, -24275, -1430, 39262), + new Location(47288, -24141, -1430, 21644), + new Location(43722, -26174, -1430, 11001), + new Location(44942, -27169, -1430, 39703), + new Location(46105, -24170, -1430, 28224), + new Location(49084, -27206, -1430, 41996), + new Location(48159, -27091, -1430, 62682), + new Location(48094, -28789, -1430, 49189), + new Location(48958, -27844, -1430, 59758), + new Location(43828, -23981, -1430, 10994), + new Location(48165, -25777, -1430, 53084), + new Location(48267, -28086, -1430, 9266), + new Location(43268, -28981, -1430, 23736), + new Location(44155, -29821, -1430, 39281), + new Location(43991, -29275, -1430, 27277), + new Location(44057, -27133, -1430, 64484), + new Location(43257, -26764, -1430, 14161), + new Location(42300, -25194, -1430, 7811), + new Location(42091, -27981, -1430, 30628), + new Location(47854, -24735, -1430, 14438) + }; + // @formatter:off + private static final int[][] GENERATOR_TRIGERS = + { + {21170102, 21170103}, + {21170104, 21170105}, + {21170106, 21170107}, + {21170108, 21170109} + }; + protected final int _chargedValues[] = new int[] {0, 0, 0, 0}; + private static final int[] LINDVIOR_SERVITOR = {25895, 25896, 25897, 29242, 29241, 29243}; + // @formatter:on + private static final NpcStringId[] GUARD_MSG = + { + NpcStringId.ACTIVATE_THE_GENERATOR_HURRY, + NpcStringId.WE_WILL_HOLD_OFF_LINDVIOR_S_MINIONS, + }; + private static final NpcStringId[] GUARD_MSG_1 = + { + NpcStringId.HOLD_ONTO_THE_GENERATOR_TO_ACTIVATE_THE_CHARGE_SKILL, + NpcStringId.THE_GENERATOR_IS_CONNECTED_TO_THE_CANNON, + }; + + public Lindvior() + { + super(); + addAttackId(LINDVIOR_GROUND, LINDVIOR_FLY, LINDVIOR_RAID); + addEnterZoneId(ZONE_ID); + addExitZoneId(ZONE_ID); + addKillId(LINDVIOR_RAID, NPC_GENERATOR); + addSkillSeeId(NPC_GENERATOR); + addSpawnId(NPC_ATTACKER_GENERATORS, NPC_ATTACKER_GENERATORS_1, LYN_DRACO_ATTACKER_GENERATORS, GENERATOR_GUARD, NPC_GENERATOR); + addFirstTalkId(NPC_GENERATOR); + addSeeCreatureId(INVISIBLE); + _zoneLair = ZoneManager.getInstance().getZoneById(ZONE_ID, L2NoSummonFriendZone.class); + // Unlock + final StatsSet info = GrandBossManager.getInstance().getStatsSet(LINDVIOR_RAID); + final long time = info.getLong("respawn_time") - System.currentTimeMillis(); + if (time > 0) + { + startQuestTimer("unlock_lindvior", time, null, null); + } + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + // Anti BUGGERS + if (!_zoneLair.isInsideZone(attacker)) + { + attacker.doDie(null); + _log.warning(getName() + ": Character: " + attacker.getName() + " attacked: " + npc.getName() + " out of the boss zone!"); + } + if (!_zoneLair.isInsideZone(npc)) + { + npc.teleToLocation(CENTER_LOCATION, true); + _log.warning(getName() + ": Character: " + attacker.getName() + " attacked: " + npc.getName() + " wich is out of the boss zone!"); + } + + double percent = ((npc.getCurrentHp() - damage) / npc.getMaxHp()) * 100; + if ((percent <= 80) && (_status == 0)) + { + _zoneLair.broadcastPacket(new OnEventTrigger(RED_ZONE_EFFECT, true)); + _zoneLair.getPlayersInside().stream().forEach(p -> + { + startQuestTimer("stop_red_zone", 10000, _lindvior, p); + p.broadcastPacket(new ExShowScreenMessage(NpcStringId.A_FEARSOME_POWER_EMANATES_FROM_LINDVIOR, ExShowScreenMessage.TOP_CENTER, 2000, true)); + }); + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_FLY, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.8); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true); + addSpawn(LINDVIOR_SERVITOR[0], loc, true); + } + _status = 1; + } + else if ((percent <= 75) && (_status == 1)) + { + _bigVortexesTask = ThreadPoolManager.schedule(() -> spawnServitor(1, 300, _lindvior.getLocation(), NPC_ATTACKER_BIG_VORTEX), 1000); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(LINDVIOR_SERVITOR[1], loc, true); + } + _zoneLair.getPlayersInside().stream().forEach(p -> p.broadcastPacket(new ExShowScreenMessage(NpcStringId.A_GIGANTIC_WHIRLWIND_HAS_APPEARED, ExShowScreenMessage.TOP_CENTER, 2000, true))); + _status = 2; + } + else if ((percent <= 60) && (_status == 2)) + { + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_GROUND, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.6); + spawnServitor(10, 2000, _lindvior.getLocation(), LINDVIOR_SERVITOR); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(LINDVIOR_SERVITOR[2], loc, true); + } + _skillCastTask = ThreadPoolManager.scheduleAtFixedRate(() -> _lindvior.doCast(SKILL_REFLECT.getSkill()), 5000, 80000); + _status = 3; + } + else if ((percent <= 40) && (_status == 3)) + { + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_FLY, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.4); + + if (SpawnTable.getInstance().getSpawns(NPC_ATTACKER_BIG_VORTEX) != null) + { + if ((_vortex != null) && (_vortex.getId() == NPC_ATTACKER_SMALL_VORTEX)) + { + _vortex.getSpawn().stopRespawn(); + _vortex.deleteMe(); + } + } + _status = 4; + } + else if ((percent <= 35) && (_status == 4)) + { + _smallVortexesTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true, 60000); + addSpawn(LINDVIOR_SERVITOR[3], loc, true); + } + + }, 20000, 60000); + _status = 5; + } + else if ((percent <= 20) && (_status == 5)) + { + if (_smallVortexesTask != null) + { + _smallVortexesTask.cancel(true); + _smallVortexesTask = null; + } + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.LINDVIOR_HAS_LANDED, 2, 5000, true)); + _lindvior.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _lindvior.setIsDead(true); + _lindvior.deleteMe(); + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_RAID, _lindvior.getLocation(), false, 0, false); + _lindvior.setCurrentHp(_lindvior.getMaxHp() * 0.2); + _bigVortexesTask = ThreadPoolManager.schedule(() -> spawnServitor(1, 300, _lindvior.getLocation(), NPC_ATTACKER_BIG_VORTEX), 1000); + for (Location loc : ATTACKER_SMALL_VORTEX_SPAWNS) + { + addSpawn(NPC_ATTACKER_SMALL_VORTEX, loc, true); + addSpawn(LINDVIOR_SERVITOR[4], loc, true); + addSpawn(LINDVIOR_SERVITOR[3], loc, true); + } + _collapseTask = ThreadPoolManager.schedule(Lindvior.this::Clean, 600000); + _status = 6; + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + protected void Clean() + { + _status = 0; + if (_socialTask != null) + { + _socialTask.cancel(false); + _socialTask = null; + } + if (_announceTask != null) + { + _announceTask.cancel(false); + _announceTask = null; + } + if (_announceProtect != null) + { + _announceProtect.cancel(false); + _announceProtect = null; + } + if (_skillCastTask != null) + { + _skillCastTask.cancel(false); + _skillCastTask = null; + } + if (_LynDracoTask != null) + { + _LynDracoTask.cancel(false); + _LynDracoTask = null; + } + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(false); + _mobsSpawnTask = null; + } + if (_collapseTask != null) + { + _collapseTask.cancel(false); + _collapseTask = null; + } + if (_bigVortexesTask != null) + { + _bigVortexesTask.cancel(false); + _bigVortexesTask = null; + } + if (_smallVortexesTask != null) + { + _smallVortexesTask.cancel(false); + _smallVortexesTask = null; + } + if (_lionel != null) + { + _lionel.deleteMe(); + } + _zoneLair.getCharactersInside().forEach(mob -> + { + if (mob.isNpc()) + { + mob.deleteMe(); + mob.setIsDead(true); + } + }); + } + + private void Fail(boolean clean) + { + if (clean) + { + Clean(); + } + _zoneLair.oustAllPlayers(); + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, false)); + cancelQuestTimers("attack_generator"); + if (GrandBossManager.getInstance().getBossStatus(LINDVIOR_RAID) != 3) + { + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, ALIVE); + } + } + + @Override + public synchronized String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon) + { + if ((skill.getId() == 15606) && (npc.getId() == NPC_GENERATOR)) + { + synchronized (_chargedValues) + { + int index = npc.getScriptValue(); + if (!hasFlag(_chargedMask, 1 << index)) + { + _chargedValues[index] += caster.isGM() ? (30 / 4) + 2 : (1 / 4) + 2; + _chargedValues[index] = Math.min(_chargedValues[index], 120); + + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 3000, player -> + { + player.sendPacket(new ExShowScreenMessage(NpcStringId.S1_HAS_CHARGED_THE_CANNON, ExShowScreenMessage.TOP_CENTER, 10000, true, caster.getName())); + player.sendPacket(new ExSendUIEvent(player, ExSendUIEvent.TYPE_NORNIL, _chargedValues[index], 120, NpcStringId.CHARGING)); + }); + if (_chargedValues[index] >= 120) + { + _chargedMask |= 1 << index; + _chargedValues[index] = 0; + } + + if (hasFlag(_chargedMask, 0xf)) + { + nextStage(3); + } + } + } + } + return null; + } + + @Override + public String onSpawn(L2Npc npc) + { + switch (npc.getId()) + { + case NPC_ATTACKER_GENERATORS: + case NPC_ATTACKER_GENERATORS_1: + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2GuardInstance.class, 800, cha -> + { + + if (cha.getId() == GENERATOR_GUARD) + { + npc.reduceCurrentHp(1, cha, null); + cha.reduceCurrentHp(1, npc, null); + } + if (cha.getId() == NPC_GENERATOR) + { + ((L2Attackable) npc).addDamageHate(cha, 500, 98); + } + }); + break; + } + case LYN_DRACO_ATTACKER_GENERATORS: + { + ((L2Attackable) npc).setCanStopAttackByTime(false); + ((L2Attackable) npc).setCanReturnToSpawnPoint(false); + startQuestTimer("attack_generator", 10000, npc, null, true); + break; + } + case GENERATOR_GUARD: + { + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + ((L2GuardInstance) npc).setIsInvul(true); + break; + } + case NPC_GENERATOR: + { + npc.disableCoreAI(true); + npc.setDisplayEffect(1); + npc.setRandomWalking(false); + npc.setIsInvul(true); // Can't get damage now + _activeMask = 0; + _chargedMask = 0; + break; + } + } + return super.onSpawn(npc); + } + + @Override + public String onSeeCreature(L2Npc npc, L2Character player, boolean isSummon) + { + setLindviorSpawnTask(); + npc.getSpawn().stopRespawn(); + npc.deleteMe(); + return super.onSeeCreature(npc, player, isSummon); + } + + private void nextStage(int _taskId) + { + switch (_taskId) + { + case 1: // Spawn Generators + { + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, true)); + int i = 0; + L2GuardInstance guard; + for (Location loc : CONTROL_GENERATOR_SPAWNS) + { + guard = (L2GuardInstance) addSpawn(NPC_GENERATOR, loc, true); + guard.setDisplayEffect(0x01); + guard.setScriptValue(i++); + _generatorSpawn.add(guard); + } + + L2Npc npc; + for (Location loc : SCHEME_GENERATOR_SPAWNS) + { + npc = addSpawn(GENERATOR_GUARD, loc, true); + npc.setRandomWalking(false); + _guardSpawn.add(npc); + } + + _mobsSpawnTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : ATTACKER_GENERATOR_SPAWNS) + { + if (getRandom(10) <= 5) + { + _monsterSpawn.add(addSpawn(NPC_ATTACKER_GENERATORS, loc, true)); + } + else + { + _monsterSpawn.add(addSpawn(NPC_ATTACKER_GENERATORS_1, loc, true)); + } + } + }, 30000, 80000); + + _dummyLindvior = addSpawn(LINDVIOR_CAMERA, 45259, -27115, -638, 41325, false, 0, false); + _announceTask = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(player -> player.sendPacket(new ExShowScreenMessage(NpcStringId.YOU_MUST_ACTIVATE_THE_4_GENERATORS, ExShowScreenMessage.TOP_CENTER, 7000, true))), 10000, 20000); + break; + } + case 2: // After activation of 4 generators, we wait to be charged + { + if (_announceTask != null) + { + _announceTask.cancel(true); + _announceTask = null; + } + _generatorSpawn.forEach(npc -> + { + npc.setDisplayEffect(1); + npc.setIsInvul(false); + npc.broadcastInfo(); + }); + + _zoneLair.getPlayersInside().forEach(player -> + { + player.sendPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, false)); + cancelQuestTimers("NPC_SHOUT"); + _guardSpawn.stream().forEach(guard -> + { + guard.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.ALL_4_GENERATORS_MUST_BE_ACTIVATED); + }); + _announceProtect = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(p -> player.sendPacket(new ExShowScreenMessage(NpcStringId.PROTECT_THE_GENERATOR, ExShowScreenMessage.TOP_CENTER, 7000, true))), 10000, 18000); + _zoneLair.broadcastPacket(new SpecialCamera(_dummyLindvior, 3300, 200, 20, 11000, 10500, 0, 8, 1, 0, 0)); + _generatorSpawn.forEach(npc -> npc.sendInfo(player)); + startQuestTimer("show_movie", 13000, null, null); + startQuestTimer("start_charge", 35000, null, null); + startQuestTimer("show_shield_animation", 2000, null, null); + }); + break; + } + case 3: // After charging all the generators + { + _zoneLair.broadcastPacket(new OnEventTrigger(ALL_GENERATORS_CONNECTED_EFFECT, true)); + if (_announceTask != null) + { + _announceTask.cancel(true); + _announceTask = null; + } + if (_announceProtect != null) + { + _announceProtect.cancel(false); + _announceProtect = null; + } + if (_skillCastTask != null) + { + _skillCastTask.cancel(true); + _skillCastTask = null; + } + if (_LynDracoTask != null) + { + _LynDracoTask.cancel(true); + _LynDracoTask = null; + } + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(true); + _mobsSpawnTask = null; + } + _monsterSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _LinDracoSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _generatorSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + _guardSpawn.forEach(npc -> + { + if (npc != null) + { + npc.deleteMe(); + } + }); + cancelQuestTimers("attack_generator"); + _lindvior2.setIsDead(true); + _lindvior2.deleteMe(); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, FIGHTING); + _lionel = addSpawn(LIONEL_HUNTER, 42630, -48231, -792, 855, false, 0, false); + + _lindvior = (L2GrandBossInstance) addSpawn(LINDVIOR_GROUND, CENTER_LOCATION, false, 0, true); + _zoneLair.broadcastPacket(new SocialAction(_lindvior.getObjectId(), 1)); + _zoneLair.getPlayersInside().forEach(_lindvior::sendInfo); + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.LINDVIOR_HAS_FALLEN_FROM_THE_SKY, ExShowScreenMessage.TOP_CENTER, 7000)); + _mobsSpawnTask = ThreadPoolManager.scheduleAtFixedRate(() -> spawnServitor(2, 1000, _lindvior.getLocation(), LINDVIOR_SERVITOR), 60000, 180000); + break; + } + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + switch (event) + { + case "unlock_lindvior": + { + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, ALIVE); + break; + } + case "stage_1_activate_generator": + { + int index = npc.getScriptValue(); + if (!hasFlag(_activeMask, 1 << index)) + { + _activeMask |= 1 << index; + npc.setDisplayEffect(0x02); + sendEventTrigger(true, GENERATOR_TRIGERS[index]); + _zoneLair.getPlayersInside().stream().forEach(p -> p.broadcastPacket(new Earthquake(p.getX(), p.getY(), p.getZ(), 20, 10))); + if (hasFlag(_activeMask, 0xf)) + { + nextStage(2); + } + } + break; + } + case "show_shield_animation": // zone brodcat shield event triger + { + _zoneLair.getPlayersInside().forEach(p -> + { + p.sendPacket(new OnEventTrigger(SECOND_STAGE_EVENT_TRIGGER, true)); + }); + _guardSpawn.stream().forEach(guard -> + { + guard.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.THE_GENERATOR_IS_CONNECTED_TO_THE_CANNON); + }); + break; + } + case "show_movie": // zone brodcat Lindvior scene movie + { + _zoneLair.getPlayersInside().forEach(p -> + { + playMovie(p, Movie.SC_LIND_OPENING); + }); + _dummyLindvior.deleteMe(); + _lindvior2 = addSpawn(LINDVIOR_FAKE, CENTER_LOCATION, false, 0, false); + _lindvior2.setTargetable(false); + _announceTask = ThreadPoolManager.scheduleAtFixedRate(() -> _zoneLair.getPlayersInside().forEach(p -> p.sendPacket(new ExShowScreenMessage(NpcStringId.CHARGE_THE_CANNON_USING_THE_GENERATOR, ExShowScreenMessage.TOP_CENTER, 7000, true))), 40000, 20000); + break; + } + case "start_charge": + { + _skillCastTask = ThreadPoolManager.scheduleAtFixedRate(() -> _generatorSpawn.forEach(generators -> + { + int index = generators.getScriptValue(); + if (!generators.isCastingNow() && (generators.getEffectList().getBuffInfoBySkillId(SKILL_RECHARGE_POSIBLE.getSkillId()) == null) && !hasFlag(_chargedMask, 1 << index)) + { + // TODO Need core implemented combo skill packet. + // On this moment player automatic charge generator if distance generator and player <= 900 + generators.doCast(SKILL_RECHARGE_POSIBLE.getSkill()); + L2World.getInstance().forEachVisibleObjectInRange(generators, L2PcInstance.class, 900, p -> + { + p.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + p.setTarget(generators); + p.doCast(RECHARGE.getSkill()); + }); + _guardSpawn.stream().forEach(guard -> + { + guard.setTarget(generators); + guard.doCast(RECHARGE.getSkill()); + guard.setIsInvul(false); + if (!guard.isDead()) + { + guard.broadcastSay(ChatType.NPC_GENERAL, GUARD_MSG_1[getRandom(GUARD_MSG_1.length)]); + } + }); + } + }), 10000, 20000); + _LynDracoTask = ThreadPoolManager.scheduleAtFixedRate(() -> + { + for (Location loc : LYN_DRACO_SPAWNS) + { + _LinDracoSpawn.add(addSpawn(LYN_DRACO_ATTACKER_GENERATORS, loc, true)); + } + }, 20000, 60000); + break; + } + case "stop_red_zone": + { + _zoneLair.broadcastPacket(new OnEventTrigger(RED_ZONE_EFFECT, false)); + break; + } + case "attack_generator": + { + if ((npc != null) && !npc.isDead()) + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2GuardInstance.class, 3000, generator -> + { + if (generator.getId() == NPC_GENERATOR) + { + npc.setTarget(generator); + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, generator.getLocation()); + if (npc.distFromMe(generator) < 500) + { + npc.reduceCurrentHp(1, generator, null); + generator.reduceCurrentHp(1, npc, null); + } + } + }); + } + break; + } + } + return null; + } + + @Override + public String onKill(L2Npc npc, L2PcInstance killer, boolean isSummon) + { + if (npc.getId() == LINDVIOR_RAID) + { + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.HONORABLE_WARRIORS_HAVE_DRIVEN_OFF_LINDVIOR_THE_EVIL_WIND_DRAGON, ExShowScreenMessage.TOP_CENTER, 10000, true)); + GrandBossManager.getInstance().setBossStatus(LINDVIOR_RAID, DEAD); + final long respawnTime = (Config.LINDVIOR_SPAWN_INTERVAL + getRandom(-Config.LINDVIOR_SPAWN_RANDOM, Config.LINDVIOR_SPAWN_RANDOM)) * 3600000; + final StatsSet info = GrandBossManager.getInstance().getStatsSet(LINDVIOR_RAID); + info.set("respawn_time", System.currentTimeMillis() + respawnTime); + GrandBossManager.getInstance().setStatsSet(LINDVIOR_RAID, info); + startQuestTimer("unlock_lindvior", respawnTime, null, null); + if (_mobsSpawnTask != null) + { + _mobsSpawnTask.cancel(true); + _mobsSpawnTask = null; + } + _zoneLair.getCharactersInside().stream().filter(L2Character::isNpc).forEach(mob -> mob.deleteMe()); + ThreadPoolManager.schedule(() -> npc.decayMe(), 10000); + _zoneLair.broadcastPacket(new OnEventTrigger(SECOND_STAGE_EVENT_TRIGGER, false)); + _zoneLair.broadcastPacket(new OnEventTrigger(FIRST_STAGE_EVENT_TRIGGER, true)); + _lionel.deleteMe(); + } + else if (npc.getId() == NPC_GENERATOR) + { + _zoneLair.broadcastPacket(new ExShowScreenMessage(NpcStringId.THE_GENERATOR_HAS_BEEN_DESTROYED, ExShowScreenMessage.TOP_CENTER, 5000, true)); + Clean(); + _collapseTask = ThreadPoolManager.schedule(() -> Fail(false), 20000); + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onFirstTalk(L2Npc npc, L2PcInstance player) + { + if (npc.getId() == NPC_GENERATOR) + { + return npc.getDisplayEffect() == 1 ? "19477.html" : "19477-01.html"; + } + return super.onFirstTalk(npc, player); + } + + @Override + public String onEnterZone(L2Character character, L2ZoneType zone) + { + if (zone.getId() == ZONE_ID) + { + if (_collapseTask != null) + { + _collapseTask.cancel(true); + _collapseTask = null; + } + } + return super.onEnterZone(character, zone); + } + + @Override + public String onExitZone(L2Character character, L2ZoneType zone) + { + if (zone.getId() == ZONE_ID) + { + if (zone.getPlayersInside().isEmpty()) + { + _collapseTask = ThreadPoolManager.schedule(() -> Fail(true), 900000); + } + } + return super.onExitZone(character, zone); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + if (event.equals("NPC_SHOUT")) + { + if ((npc != null) && !npc.isDead()) + { + npc.broadcastSay(ChatType.NPC_GENERAL, GUARD_MSG[getRandom(GUARD_MSG.length)]); + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + } + } + } + + private void sendEventTrigger(boolean status, int... triggers) + { + IClientOutgoingPacket[] pakets = new IClientOutgoingPacket[triggers.length]; + for (int i = 0; i < triggers.length; i++) + { + pakets[i] = new OnEventTrigger(triggers[i], status); + } + for (IClientOutgoingPacket packet : pakets) + { + _zoneLair.broadcastPacket(packet); + } + } + + private void spawnServitor(int count, int radius, Location loc, int... npcIds) + { + int x = loc.getX(), y = loc.getY(); + if (radius > 0) + { + x += Rnd.get(-radius, radius); + y += Rnd.get(-radius, radius); + } + + for (int i = 0; i < count; i++) + { + _monsterSpawn.add(addSpawn(npcIds[getRandom(npcIds.length)], x, y, loc.getZ(), loc.getHeading(), true, 0, true)); + } + } + + private static boolean hasFlag(int val, int flag) + { + return (val & flag) == flag; + } + + public void setLindviorSpawnTask() + { + synchronized (this) + { + if (_socialTask == null) + { + _socialTask = ThreadPoolManager.schedule(() -> nextStage(1), 3000); + } + } + } + + @RegisterEvent(EventType.ON_CREATURE_DAMAGE_RECEIVED) + @RegisterType(ListenerRegisterType.NPC) + @Id(LINDVIOR_FLY) + @Id(LINDVIOR_RAID) + @Id(LINDVIOR_GROUND) + public void onCreatureDamageReceived(OnCreatureDamageReceived event) + { + _zoneLair.getPlayersInside().stream().forEach(p -> + { + switch (_status) + { + case 0: + case 1: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 1, -1, 0.015, true); + break; + } + case 2: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 2, -1, 0.015, true); + break; + } + case 3: + case 4: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 3, -1, 0.015, true); + break; + } + case 5: + { + giveItemRandomly(p, null, LINDVIORS_SCALE, 4, -1, 0.015, true); + break; + } + } + }); + } + + public static void main(String[] args) + { + new Lindvior(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java new file mode 100644 index 0000000000..d60c088f9f --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LindviorBoss.java @@ -0,0 +1,175 @@ +/* + * 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 ai.bosses.Lindvior; + +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.SkillHolder; + +import ai.AbstractNpcAI; + +/** + * LindviorBoss AI + * @author Gigi + * @date 2017-08-02 - [11:05:21] + */ +public class LindviorBoss extends AbstractNpcAI +{ + // Boss + private static final int LINDVIOR_GROUND = 25899; + private static final int LINDVIOR_RAID = 29240; + private static final int LINDVIOR_FLY = 19424; + // Skills + private static final SkillHolder SKILL_FLY_UP = new SkillHolder(15278, 1); + private static final SkillHolder SKILL_RABIES = new SkillHolder(15269, 1); + private static final SkillHolder SKILL_FLY = new SkillHolder(15279, 1); + private static final SkillHolder MASS_HELL_BINDING = new SkillHolder(11052, 6); + private static final SkillHolder MIGHTY_WIND_STRIKE = new SkillHolder(15274, 1); + private static final SkillHolder WIND_PULL = new SkillHolder(15591, 1); + private static final SkillHolder LINDVIORS_JUMP = new SkillHolder(15430, 1); + private static final SkillHolder BODY_SLAM = new SkillHolder(15271, 1); + private static final SkillHolder SOAR = new SkillHolder(15279, 1); + private static final SkillHolder WIND_BREAT = new SkillHolder(15272, 1); + private static final SkillHolder TAIL_SWIPE = new SkillHolder(15273, 1); + private static final SkillHolder TORNADO = new SkillHolder(15275, 1); + private static final SkillHolder LINDVIORS_ATTACK = new SkillHolder(15600, 1); + // Chances + private final static int CHANCE_MIGHTY_WIND_STRIKE = 9; + private final static int CHANCE_WIND_PULL = 4; + private final static int CHANCE_LINDVIORS_JUMP = 7; + private final static int CHANCE_BODY_SLAM = 2; + private final static int CHANCE_SOAR = 8; + private final static int CHANCE_WIND_BREAT = 3; + private final static int CHANCE_TAIL_SWIPE = 5; + private final static int CHANCE_TORNADO = 6; + private final static int CHANCE_LINDVIORS_ATTACK = 1; + + public LindviorBoss() + { + super(); + addAttackId(LINDVIOR_GROUND, LINDVIOR_FLY, LINDVIOR_RAID); + addSpawnId(LINDVIOR_FLY); + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + double percent = ((npc.getCurrentHp() - damage) / npc.getMaxHp()) * 100; + final int chance = getRandom(100); + switch (npc.getId()) + { + case LINDVIOR_GROUND: + { + if ((percent <= 80) && npc.isScriptValue(0)) + { + + npc.doCast(SKILL_FLY_UP.getSkill()); + npc.doCast(SKILL_RABIES.getSkill()); + npc.setScriptValue(1); + } + else if ((percent <= 40) && (npc.isScriptValue(1))) + { + npc.doCast(SKILL_FLY.getSkill()); + npc.setScriptValue(2); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_MIGHTY_WIND_STRIKE)) + { + npc.setTarget(attacker); + npc.doCast(MIGHTY_WIND_STRIKE.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_PULL)) + { + npc.setTarget(attacker); + npc.doCast(WIND_PULL.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_LINDVIORS_JUMP)) + { + npc.setTarget(attacker); + npc.doCast(LINDVIORS_JUMP.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_BODY_SLAM)) + { + npc.setTarget(attacker); + npc.doCast(BODY_SLAM.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TAIL_SWIPE)) + { + npc.setTarget(attacker); + npc.doCast(TAIL_SWIPE.getSkill()); + } + break; + } + case LINDVIOR_FLY: + { + if (!npc.isCastingNow() && (chance <= CHANCE_SOAR)) + { + npc.setTarget(attacker); + npc.doCast(SOAR.getSkill()); + } + break; + } + case LINDVIOR_RAID: + { + if ((percent <= 20) && (npc.isScriptValue(0))) + { + npc.doCast(SKILL_FLY.getSkill()); + npc.setScriptValue(1); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_BREAT)) + { + npc.setTarget(attacker); + npc.doCast(WIND_BREAT.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_WIND_PULL)) + { + npc.setTarget(attacker); + npc.doCast(WIND_PULL.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TAIL_SWIPE)) + { + npc.setTarget(attacker); + npc.doCast(TAIL_SWIPE.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_TORNADO)) + { + npc.setTarget(attacker); + npc.doCast(TORNADO.getSkill()); + } + else if (!npc.isCastingNow() && (chance <= CHANCE_LINDVIORS_ATTACK)) + { + npc.setTarget(attacker); + npc.doCast(LINDVIORS_ATTACK.getSkill()); + } + break; + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + npc.setRandomWalking(true); + npc.doCast(MASS_HELL_BINDING.getSkill()); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new LindviorBoss(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java new file mode 100644 index 0000000000..846ada3442 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/LionelHunter.java @@ -0,0 +1,67 @@ +/* + * 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 ai.bosses.Lindvior; + +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.instancemanager.WalkingManager; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.NpcStringId; + +import ai.AbstractNpcAI; + +/** + * Lionel Hunter AI + * @author Gigi + * @date 2017-07-23 - [22:54:59] + */ +public class LionelHunter extends AbstractNpcAI +{ + // Npc + private static final int LIONEL_HUNTER = 33886; + // Misc + private static final String ROUTE_NAME = "Rune_Lionel"; + + public LionelHunter() + { + addSpawnId(LIONEL_HUNTER); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + if (event.equals("NPC_SHOUT") && (npc != null)) + { + npc.broadcastSay(ChatType.NPC_GENERAL, NpcStringId.WE_JUST_LOCATED_LINDVIOR_THOSE_WHO_ARE_WILLING_TO_FIGHT_CAN_DO_SO_AT_ANY_TIME_NOW); + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + } + } + + @Override + public String onSpawn(L2Npc npc) + { + getTimers().addTimer("NPC_SHOUT", (10 + getRandom(5)) * 1000, npc, null); + WalkingManager.getInstance().startMoving(npc, ROUTE_NAME); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new LionelHunter(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java new file mode 100644 index 0000000000..d9bf024d24 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/bosses/Lindvior/Vortex.java @@ -0,0 +1,176 @@ +/* + * 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 ai.bosses.Lindvior; + +import java.util.Collection; + +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.Location; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.network.serverpackets.FlyToLocation; +import com.l2jmobius.gameserver.network.serverpackets.ValidateLocation; + +import ai.AbstractNpcAI; + +/** + * Vortex AI + * @author Gigi + * @date 2017-07-23 - [10:32:50] + */ +public class Vortex extends AbstractNpcAI +{ + private static final int SMALL_VORTEX = 25898; + private static final int BIG_VORTEX = 19427; + + public Vortex() + { + super(); + addSeeCreatureId(SMALL_VORTEX, BIG_VORTEX); + addSpawnId(SMALL_VORTEX, BIG_VORTEX); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + switch (event) + { + case "rnd_small": + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 250, attackers -> + { + if ((attackers != null) && !attackers.isDead() && !attackers.isAlikeDead()) + { + attackers.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + final int radians = (int) Math.toRadians(npc.calculateDirectionTo(attackers)); + final int x = (int) (attackers.getX() + (600 * Math.cos(radians))); + final int y = (int) (attackers.getY() + (600 * Math.sin(radians))); + final int z = attackers.getZ(); + final Location loc = GeoEngine.getInstance().canMoveToTargetLoc(attackers.getX(), attackers.getY(), attackers.getZ(), x, y, z, attackers.getInstanceWorld()); + attackers.broadcastPacket(new FlyToLocation(attackers, x, y, z, FlyToLocation.FlyType.THROW_UP, 800, 800, 800)); + attackers.setXYZ(loc); + attackers.broadcastPacket(new ValidateLocation(attackers)); + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player); + startQuestTimer("stop_knock_down", 5000, npc, attackers); + startQuestTimer("despawn_small", 5000, npc, null); + } + }); + break; + } + case "rnd_big": + { + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 500, attackers -> + { + if ((attackers != null) && !attackers.isDead() && !attackers.isAlikeDead()) + { + attackers.setCurrentHp(1.0); + attackers.setCurrentMp(1.0); + attackers.setCurrentCp(1.0); + startQuestTimer("despawn_big", 600000, npc, null); + } + }); + break; + } + case "despawn_small": + { + if (npc != null) + { + cancelQuestTimers("rnd_small"); + npc.getSpawn().stopRespawn(); + npc.doDie(null); + } + break; + } + case "despawn_big": + { + if (npc != null) + { + cancelQuestTimers("despawn_big"); + npc.getSpawn().stopRespawn(); + npc.deleteMe(); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSeeCreature(L2Npc npc, L2Character player, boolean isSummon) + { + switch (npc.getId()) + { + case SMALL_VORTEX: + { + startQuestTimer("rnd_small", 5000, npc, null, true); + break; + } + case BIG_VORTEX: + { + startQuestTimer("rnd_big", 10000, npc, null, true); + break; + } + } + return super.onSeeCreature(npc, player, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + switch (npc.getId()) + { + case SMALL_VORTEX: + { + attackRandomTarget(npc); + npc.setRandomWalking(true); + npc.setIsRunning(true); + break; + } + case BIG_VORTEX: + { + attackRandomTarget(npc); + npc.setRandomWalking(true); + npc.setIsRunning(true); + break; + } + } + return super.onSpawn(npc); + } + + private void attackRandomTarget(L2Npc npc) + { + final Collection players = L2World.getInstance().getVisibleObjects(npc, L2PcInstance.class); + { + if ((players == null) || players.isEmpty()) + { + return; + } + if (players.size() > 0) + { + addAttackPlayerDesire(npc, players.stream().findAny().get()); + } + } + } + + public static void main(String[] args) + { + new Vortex(); + } +} diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/08500-08599.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/08500-08599.xml index 75fd3434dd..5799fc23b8 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/08500-08599.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/08500-08599.xml @@ -1954,7 +1954,7 @@ - + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19400-19499.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19400-19499.xml index 6be32ec2b6..6118ac9716 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19400-19499.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19400-19499.xml @@ -825,58 +825,76 @@ - + DRAGON FEMALE - - - + + - + - - + + - + + - - + - - + + + + + + + + + + - + DRAGON FEMALE - - - + + - + - - + + - + + - - + - - - + + + + + + + + + + + + + + + @@ -984,7 +1002,7 @@ - + @@ -2307,7 +2325,7 @@ - + ETC FEMALE @@ -2323,7 +2341,10 @@ - + + + + @@ -2351,7 +2372,7 @@ - + ETC FEMALE @@ -2362,7 +2383,7 @@ - + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/25800-25899.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/25800-25899.xml index 699514cf2e..48950deb04 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/25800-25899.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/25800-25899.xml @@ -4800,7 +4800,7 @@ - + DRAGON FEMALE @@ -4810,8 +4810,8 @@ - - + + @@ -4831,7 +4831,7 @@ - + DRAGON FEMALE @@ -4862,7 +4862,7 @@ - + DRAGON FEMALE @@ -4886,6 +4886,12 @@ + + + + + + @@ -4893,15 +4899,18 @@ - + + + + DRAGON FEMALE - - + + @@ -4919,29 +4928,29 @@ - + true + - - + DRAGON FEMALE - - + + + - - + + - - + + - @@ -4950,11 +4959,16 @@ + + + + + - - + + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/29200-29299.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/29200-29299.xml index b24d4bd89f..1e4f153abc 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/29200-29299.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/29200-29299.xml @@ -2046,13 +2046,13 @@ - - + DRAGON FEMALE + - + @@ -2066,91 +2066,123 @@ - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2163,7 +2195,7 @@ - + DRAGON FEMALE diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/skills/15600-15699.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/skills/15600-15699.xml index 2e0705da15..c7d1a933ea 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/stats/skills/15600-15699.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/skills/15600-15699.xml @@ -49,23 +49,38 @@ 2 1800 - - + icon.skill0005 + 20 A2 + 1000 + 1000 1 - 25000 + 10000 + SELF + RANGE + NOT_FRIEND - icon.skill1449 + icon.skill14444 A1 + 1 900 10000 -2 - 200 + 200 + TARGET + SINGLE + + + + 19477 + + + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/zones/no_summon_friend.xml b/L2J_Mobius_3.0_Helios/dist/game/data/zones/no_summon_friend.xml index fdd074bb36..b00ebdddd6 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/zones/no_summon_friend.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/zones/no_summon_friend.xml @@ -167,6 +167,20 @@ + + + + + + + + + + + + + + diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java index b0a99b5244..3bd48421fc 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java @@ -893,6 +893,13 @@ public final class Config public static int KELBIM_SPAWN_INTERVAL; public static int KELBIM_SPAWN_RANDOM; + // Lindvior + public static int LINDVIOR_SPAWN_INTERVAL; + public static int LINDVIOR_SPAWN_RANDOM; + public static int LINDVIOR_MIN_PLAYERS; + public static int LINDVIOR_MAX_PLAYERS; + public static int LINDVIOR_MIN_PLAYER_LVL; + // Anakim public static int ANAKIM_MIN_PLAYERS; public static int ANAKIM_MAX_PLAYERS; @@ -2227,6 +2234,11 @@ public final class Config LILITH_SPAWN_RANDOM = GrandBossSettings.getInt("RandomOfLilithSpawn", 148); LILITH_MIN_PLAYER_LVL = GrandBossSettings.getInt("LilithMinPlayerLvl", 85); LILITH_MAX_PLAYER_LVL = GrandBossSettings.getInt("LilithMaxPlayerLvl", 89); + LINDVIOR_SPAWN_INTERVAL = GrandBossSettings.getInt("IntervalOfLindviorSpawn", 264); + LINDVIOR_SPAWN_RANDOM = GrandBossSettings.getInt("RandomOfLindviorSpawn", 72); + LINDVIOR_MIN_PLAYERS = GrandBossSettings.getInt("LindviorMinPlayers", 49); + LINDVIOR_MAX_PLAYERS = GrandBossSettings.getInt("LindviorMaxPlayers", 112); + LINDVIOR_MIN_PLAYER_LVL = GrandBossSettings.getInt("LindviorMinPlayerLvl", 99); // Gracia Seeds final PropertiesParser GraciaSeedsSettings = new PropertiesParser(GRACIASEEDS_CONFIG_FILE); diff --git a/L2J_Mobius_3.0_Helios/readme.txt b/L2J_Mobius_3.0_Helios/readme.txt index a66457bb84..f37ac98606 100644 --- a/L2J_Mobius_3.0_Helios/readme.txt +++ b/L2J_Mobius_3.0_Helios/readme.txt @@ -20,7 +20,6 @@ What is done TODO list -Helios grandboss --Lindvior -Trasken -Underground five man dungeons -Check all quests rewards