From a915abe001352166ff0380969b8a3646ef68b907 Mon Sep 17 00:00:00 2001 From: MobiusDev <8391001+MobiusDevelopment@users.noreply.github.com> Date: Sun, 15 Jan 2017 18:06:50 +0000 Subject: [PATCH] Balok AI. Contributed by gigilo1968. --- .../dist/game/data/html/default/33523.htm | 2 +- .../data/instances/Bosses/BalokWarzone.xml | 61 +++ .../scripts/ai/bosses/Balok/BalokWarzone.java | 348 ++++++++++++++++++ .../scripts/ai/bosses/Balok/condNoParty.html | 3 + .../ai/bosses/Balok/condNoPartyLeader.html | 3 + .../dist/game/data/stats/npcs/23100-23199.xml | 7 + .../dist/game/data/stats/npcs/29200-29299.xml | 16 +- .../game/data/stats/skills/02300-02399.xml | 3 + 8 files changed, 433 insertions(+), 10 deletions(-) create mode 100644 L2J_Mobius_Underground/dist/game/data/instances/Bosses/BalokWarzone.xml create mode 100644 L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/BalokWarzone.java create mode 100644 L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoParty.html create mode 100644 L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoPartyLeader.html diff --git a/L2J_Mobius_Underground/dist/game/data/html/default/33523.htm b/L2J_Mobius_Underground/dist/game/data/html/default/33523.htm index 74535311bc..d43d49c9cb 100644 --- a/L2J_Mobius_Underground/dist/game/data/html/default/33523.htm +++ b/L2J_Mobius_Underground/dist/game/data/html/default/33523.htm @@ -1,4 +1,4 @@ Crystal Prison Entrance Portal:
- + \ No newline at end of file diff --git a/L2J_Mobius_Underground/dist/game/data/instances/Bosses/BalokWarzone.xml b/L2J_Mobius_Underground/dist/game/data/instances/Bosses/BalokWarzone.xml new file mode 100644 index 0000000000..cd5ffafb4f --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/data/instances/Bosses/BalokWarzone.xml @@ -0,0 +1,61 @@ + + + + diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/BalokWarzone.java b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/BalokWarzone.java new file mode 100644 index 0000000000..86054adf10 --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/BalokWarzone.java @@ -0,0 +1,348 @@ +/* + * 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.Balok; + +import java.util.ArrayList; +import java.util.List; + +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ai.CtrlIntention; +import com.l2jmobius.gameserver.enums.Movie; +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.L2PcInstance; +import com.l2jmobius.gameserver.model.events.impl.character.OnCreatureSee; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.instancezone.Instance; +import com.l2jmobius.gameserver.model.skills.Skill; +import com.l2jmobius.gameserver.network.SystemMessageId; +import com.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; + +import instances.AbstractInstance; + +/** + * Baylor Warzone instance zone. + * @author LasTravel, Gigi + * @Video https://www.youtube.com/watch?v=w_-SNNPoulo&t=204s + */ +public final class BalokWarzone extends AbstractInstance +{ + // NPCs + private static final int BALOK = 29218; + private static final int MINION = 23123; + private static final int HELL_DISCIPLE = 29219; + private static final int ENTRANCE_PORTAL = 33523; + private static final int INVISIBLE_NPC_1 = 29106; + private static final int BLUE_GRAVE = 19562; // TODO need find retail npc ID + // Item + private static final int PRISON_KEY = 10015; + // Skills + private static final SkillHolder DARKNESS_DRAIN = new SkillHolder(14367, 1); + private static final SkillHolder REAR_DESTROY = new SkillHolder(14576, 1); + private static final SkillHolder INVINCIBILITY_ACTIVATION = new SkillHolder(14190, 1); + private static final SkillHolder EARTH_DEMOLITION = new SkillHolder(14246, 1); + private static final SkillHolder IMPRISION = new SkillHolder(5226, 1); + // Misc + private static final int TEMPLATE_ID = 167; + //@formatter:off + private static final int[][] MINION_SPAWN = + { + {154592, 141488, -12738, 26941}, + {154759, 142073, -12738, 32333}, + {154158, 143112, -12738, 43737}, + {152963, 143102, -12738, 53988}, + {152360, 142067, -12740, 0}, + {152530, 141457, -12740, 7246}, + {153571, 140878, -12738, 16756}, + {154174, 141057, -12738, 22165} + }; + private static final int[][] PRISONS_SPAWN = + { + {154428, 140551, -12712}, + {155061, 141204, -12704}, + {155268, 142097, -12712}, + {154438, 143581, -12712}, + {152695, 143560, -12704}, + {151819, 142063, -12712}, + {152055, 141231, -12712}, + {153608, 140371, -12712} + }; + //@formatter:on + private final List minionList = new ArrayList<>(); + private L2Npc currentMinion; + private L2Npc balok; + + public BalokWarzone() + { + super(TEMPLATE_ID); + addStartNpc(ENTRANCE_PORTAL); + addTalkId(ENTRANCE_PORTAL); + addInstanceCreatedId(TEMPLATE_ID); + addAttackId(BALOK); + addSkillSeeId(BALOK); + addKillId(BALOK, MINION); + addSpellFinishedId(BALOK); + addSpawnId(INVISIBLE_NPC_1); + setCreatureSeeId(this::onCreatureSee, INVISIBLE_NPC_1); + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.equals("enterInstance")) + { + if (hasQuestItems(player, PRISON_KEY)) + { + takeItems(player, PRISON_KEY, -1); + } + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player) + { + final Instance world = npc.getInstanceWorld(); + if (isInInstance(world)) + { + switch (event) + { + case "stage_1_start": + { + playMovie(world.getPlayers(), Movie.SI_BARLOG_STORY); + getTimers().addTimer("stage_1_balok_intro", 72500, npc, null); + break; + } + case "stage_1_balok_intro": + { + playMovie(world.getPlayers(), Movie.SI_BARLOG_OPENING); + getTimers().addTimer("stage_1_spawn_balok", 21300, npc, null); + break; + } + case "stage_1_spawn_balok": + { + balok = addSpawn(BALOK, 153573, 142071, -12738, 16565, false, 0, false, world.getId()); + world.setStatus(1); + break; + } + case "stage_last_send_minions": + { + + L2Npc minion = minionList.get(Rnd.get(minionList.size())); + if (minion != null) + { + minion.setIsRunning(true); + ((L2Attackable) minion).setCanReturnToSpawnPoint(false); + currentMinion = minion; + getTimers().addTimer("stage_last_minion_walk", 2000, minion, player); + } + + break; + } + case "stage_last_minion_walk": + { + if (npc.getId() == MINION) + { + if (npc.calculateDistance(balok.getXdestination(), balok.getYdestination(), 0, false, true) < (800 * 800)) + { + npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(balok.getX() + 100, balok.getY() + 50, balok.getZ(), balok.getHeading())); + getTimers().addTimer("stage_last_minion_walk", 2000, npc, player); + } + else + { + npc.stopSkillEffects(INVINCIBILITY_ACTIVATION.getSkill()); + balok.setTarget(npc); + balok.doCast(DARKNESS_DRAIN.getSkill()); + } + } + break; + } + case "stage_spawn_apostols": + { + for (int i = 0; i < 4; i++) + { + L2Npc disciple = addSpawn(HELL_DISCIPLE, npc.getX(), npc.getY(), npc.getZ(), 0, true, 600000, false); + addAttackPlayerDesire(disciple, player); + } + break; + } + } + } + } + + @Override + public String onAttack(L2Npc npc, L2PcInstance attacker, int damage, boolean isSummon) + { + final Instance world = npc.getInstanceWorld(); + if (isInInstance(world)) + { + if (npc.getId() == BALOK) + { + if ((npc.getCurrentHp() < (npc.getMaxHp() * 0.85)) && (world.getStatus() == 1)) + { + for (int[] a : MINION_SPAWN) + { + L2Npc minion = addSpawn(MINION, a[0], a[1], a[2], a[3], false, 0, false, world.getId()); + minionList.add(minion); + INVINCIBILITY_ACTIVATION.getSkill().applyEffects(minion, minion); + world.setStatus(2); + } + } + else if ((npc.getCurrentHp() < (npc.getMaxHp() * 0.50)) && (world.getStatus() == 2)) + { + if (npc.isScriptValue(0)) + { + INVINCIBILITY_ACTIVATION.getSkill().applyEffects(npc, npc); + npc.setScriptValue(1); + } + L2World.getInstance().forEachVisibleObjectInRange(npc, L2PcInstance.class, 300, instPlayer -> + { + if ((instPlayer == null) || (Rnd.get(100) > 2)) + { + return; + } + npc.setTarget(instPlayer); + npc.doCast(IMPRISION.getSkill()); + int[] randomJail = PRISONS_SPAWN[Rnd.get(PRISONS_SPAWN.length)]; // Random jail + instPlayer.teleToLocation(randomJail[0], randomJail[1], randomJail[2]); + world.broadcastPacket(new ExShowScreenMessage("$s1, locked away in the prison.".replace("$s1", instPlayer.getName()), 5000)); + }); + getTimers().addTimer("stage_last_send_minions", 2000, npc, null); + } + else if ((npc.getCurrentHp() < (npc.getMaxHp() * 0.30))) + { + npc.setTarget(attacker); + npc.doCast(EARTH_DEMOLITION.getSkill()); + // TODO: does not spawn + addSpawn(BLUE_GRAVE, npc.getX() + 100, npc.getY() + 50, npc.getZ(), npc.getHeading(), false, 0, false, world.getId()); + getTimers().addTimer("stage_spawn_apostols", 2000, npc, attacker); + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill) + { + final Instance world = npc.getInstanceWorld(); + if (isInInstance(world)) + { + if (world != null) + { + if (skill.getId() == DARKNESS_DRAIN.getSkillId()) + { + if (!currentMinion.isDead()) + { + balok.setCurrentHp(balok.getCurrentHp() + currentMinion.getMaxHp()); + } + } + } + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onKill(L2Npc npc, L2PcInstance player, boolean isPet) + { + final Instance world = npc.getInstanceWorld(); + + if (npc == balok) + { + if (world.getAliveNpcs(BALOK).isEmpty()) + { + world.getAliveNpcs(MINION).forEach(guard -> guard.doDie(null)); + world.removeNpcs(); + world.finishInstance(); + world.broadcastPacket(SystemMessage.getSystemMessage(SystemMessageId.THIS_DUNGEON_WILL_EXPIRE_IN_S1_MINUTE_S_YOU_WILL_BE_FORCED_OUT_OF_THE_DUNGEON_WHEN_THE_TIME_EXPIRES).addInt((int) 5.0D)); + } + else + { + world.setReenterTime(); + } + } + else if (npc == currentMinion) + { + synchronized (minionList) + { + if (minionList.contains(npc)) + { + minionList.remove(npc); + + if (minionList.size() > 0) + { + startQuestTimer("stage_last_send_minions", 2000, npc, null); + } + else + { + balok.stopSkillEffects(INVINCIBILITY_ACTIVATION.getSkill()); + } + } + } + } + return super.onKill(npc, player, isPet); + } + + public void onCreatureSee(OnCreatureSee event) + { + final L2Character creature = event.getSeen(); + final L2Npc npc = (L2Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + if (isInInstance(world) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + getTimers().addTimer("stage_1_start", 60000, npc, null); + } + } + + @Override + public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, L2Object[] targets, boolean isSummon) + { + if (!npc.isDead() && npc.getEffectList().isAffectedBySkill(INVINCIBILITY_ACTIVATION.getSkillId()) /* && caster.isBehindTarget() */) // TODO: does not work + { + npc.setTarget(caster); + npc.doCast(REAR_DESTROY.getSkill()); + if (getRandom(100) < 30) + { + npc.stopSkillEffects(INVINCIBILITY_ACTIVATION.getSkill()); + } + } + return super.onSkillSee(npc, caster, skill, targets, isSummon); + } + + @Override + public String onSpawn(L2Npc npc) + { + if (npc.getId() == INVISIBLE_NPC_1) + { + npc.initSeenCreatures(); + } + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new BalokWarzone(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoParty.html b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoParty.html new file mode 100644 index 0000000000..942bd3626a --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Prison Entrance Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoPartyLeader.html b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoPartyLeader.html new file mode 100644 index 0000000000..8e110e82f1 --- /dev/null +++ b/L2J_Mobius_Underground/dist/game/data/scripts/ai/bosses/Balok/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Prison Entrance Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_Underground/dist/game/data/stats/npcs/23100-23199.xml b/L2J_Mobius_Underground/dist/game/data/stats/npcs/23100-23199.xml index 0ff29fcc94..0afb550931 100644 --- a/L2J_Mobius_Underground/dist/game/data/stats/npcs/23100-23199.xml +++ b/L2J_Mobius_Underground/dist/game/data/stats/npcs/23100-23199.xml @@ -1388,6 +1388,13 @@ + + + + + + + diff --git a/L2J_Mobius_Underground/dist/game/data/stats/npcs/29200-29299.xml b/L2J_Mobius_Underground/dist/game/data/stats/npcs/29200-29299.xml index 51bcafda99..42dcab6b01 100644 --- a/L2J_Mobius_Underground/dist/game/data/stats/npcs/29200-29299.xml +++ b/L2J_Mobius_Underground/dist/game/data/stats/npcs/29200-29299.xml @@ -945,14 +945,8 @@ - - - - - - - - + + DEMONIC @@ -976,9 +970,13 @@ - + + + + + diff --git a/L2J_Mobius_Underground/dist/game/data/stats/skills/02300-02399.xml b/L2J_Mobius_Underground/dist/game/data/stats/skills/02300-02399.xml index 9ae2ce0071..0146659ffd 100644 --- a/L2J_Mobius_Underground/dist/game/data/stats/skills/02300-02399.xml +++ b/L2J_Mobius_Underground/dist/game/data/stats/skills/02300-02399.xml @@ -1919,6 +1919,9 @@ + + + 100