diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/34488-03.html b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/34488-03.html new file mode 100644 index 0000000000..0e8ca33ac7 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/34488-03.html @@ -0,0 +1,5 @@ +Heart of Tsunami:
+(A thundering voice speaks in your head.)
+Maximum of 200 player can enter.
+(You cannot challenge Fafurion at this time.)
+ \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/EliteWizard.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/EliteWizard.java new file mode 100644 index 0000000000..4658164ce3 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/EliteWizard.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.Fafurion; + +import org.l2jmobius.commons.util.CommonUtil; +import org.l2jmobius.gameserver.model.actor.Creature; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.skills.SkillCaster; +import org.l2jmobius.gameserver.model.variables.NpcVariables; + +import ai.AbstractNpcAI; + +/** + * @author NviX + */ +public class EliteWizard extends AbstractNpcAI +{ + // Npc + private static final int ELITE_WIZARD = 29373; + // Skills + private static final SkillHolder WATER_ARROW = new SkillHolder(32740, 1); + private static final SkillHolder ARROW_FLUSH = new SkillHolder(32741, 1); + + private EliteWizard() + { + registerMobs(ELITE_WIZARD); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + switch (event) + { + case "MANAGE_SKILLS": + { + if (npc != null) + { + manageSkills(npc); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + if (npc.getId() == ELITE_WIZARD) + { + if (skill == null) + { + refreshAiParams(attacker, npc, (damage * 1000)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.25)) + { + refreshAiParams(attacker, npc, ((damage / 3) * 100)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) + { + refreshAiParams(attacker, npc, (damage * 20)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.75)) + { + refreshAiParams(attacker, npc, (damage * 10)); + } + else + { + refreshAiParams(attacker, npc, ((damage / 3) * 20)); + } + manageSkills(npc); + } + + return super.onAttack(npc, attacker, damage, isSummon); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage) + { + refreshAiParams(attacker, npc, damage, damage); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage, int aggro) + { + final int newAggroVal = damage + getRandom(3000); + final int aggroVal = aggro + 1000; + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + if (attacker == vars.getObject("c_quest" + i, Creature.class)) + { + if (vars.getInt("i_quest" + i) < aggroVal) + { + vars.set("i_quest" + i, newAggroVal); + } + return; + } + } + final int index = CommonUtil.getIndexOfMinValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + vars.set("i_quest" + index, newAggroVal); + vars.set("c_quest" + index, attacker); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + startQuestTimer("MANAGE_SKILLS", 1000, npc, null); + return super.onSpellFinished(npc, player, skill); + } + + private void manageSkills(Npc npc) + { + if (npc.isCastingNow(SkillCaster::isAnyNormalType) || npc.isCoreAIDisabled() || !npc.isInCombat()) + { + return; + } + + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + final Creature attacker = vars.getObject("c_quest" + i, Creature.class); + if ((attacker == null) || ((npc.calculateDistance3D(attacker) > 9000) || attacker.isDead())) + { + vars.set("i_quest" + i, 0); + } + } + final int index = CommonUtil.getIndexOfMaxValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + final Creature player = vars.getObject("c_quest" + index, Creature.class); + final int i2 = vars.getInt("i_quest" + index); + if ((i2 > 0) && (getRandom(100) < 70)) + { + vars.set("i_quest" + index, 500); + } + + SkillHolder skillToCast = null; + if ((player != null) && !player.isDead()) + { + if (getRandom(100) < 30) + { + skillToCast = ARROW_FLUSH; + } + else + { + skillToCast = WATER_ARROW; + } + } + + if ((skillToCast != null) && SkillCaster.checkUseConditions(npc, skillToCast.getSkill())) + { + npc.setTarget(player); + npc.doCast(skillToCast.getSkill()); + } + } + + public static void main(String[] args) + { + new EliteWizard(); + } +} diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java index c0d58bd844..848a76a845 100644 --- a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java @@ -14,19 +14,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package ai.bosses.Fafurion; import java.util.List; import org.l2jmobius.Config; +import org.l2jmobius.gameserver.enums.Movie; +import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; import org.l2jmobius.gameserver.instancemanager.GrandBossManager; import org.l2jmobius.gameserver.instancemanager.ZoneManager; import org.l2jmobius.gameserver.model.Location; import org.l2jmobius.gameserver.model.Party; import org.l2jmobius.gameserver.model.StatSet; import org.l2jmobius.gameserver.model.World; -import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.zone.type.NoRestartZone; import org.l2jmobius.gameserver.network.NpcStringId; @@ -42,59 +45,76 @@ public class Fafurion extends AbstractNpcAI // NPCs private static final int HEART_OF_TSUNAMI = 34488; private static final int FAFURION_GRANDBOSS_ID = 19740; - private static final int FAFURION_FINAL_FORM = 29367; + private static final int FAFURION_STAGE_1 = 29361; + private static final int FAFURION_STAGE_2 = 29362; + private static final int FAFURION_STAGE_3 = 29363; + private static final int FAFURION_STAGE_4 = 29364; + private static final int FAFURION_STAGE_5 = 29365; + private static final int FAFURION_STAGE_6 = 29366; + private static final int FAFURION_STAGE_7 = 29367; + private static final int EMERALD_DRAGON = 29368; + private static final int BLUE_WATER_DRAGON = 29369; + private static final int FAFURION_DEFENDER = 29370; // Item private static final int FONDUS_STONE = 80322; + // Zone + private static final NoRestartZone FAFURION_ZONE = ZoneManager.getInstance().getZoneById(85002, NoRestartZone.class); // Locations - private static final Location ENTER_NPC_LOC = new Location(190856, 257112, -3328); private static final Location RAID_ENTER_LOC = new Location(180059, 212896, -14727); private static final Location FAFURION_SPAWN_LOC = new Location(180712, 210664, -14823, 22146); - // Zone - private static final NoRestartZone zone = ZoneManager.getInstance().getZoneById(85002, NoRestartZone.class); // Fafurion Nest zone // Status private static final int ALIVE = 0; private static final int WAITING = 1; private static final int FIGHTING = 2; private static final int DEAD = 3; // Misc + private static final int MAX_PEOPLE = 200; private static final int RAID_DURATION = 5; // hours + private static GrandBossInstance _fafurion; + private int _stage; private Fafurion() { addStartNpc(HEART_OF_TSUNAMI); addTalkId(HEART_OF_TSUNAMI); addFirstTalkId(HEART_OF_TSUNAMI); - addKillId(FAFURION_FINAL_FORM); - final StatSet info = GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID); - final long respawnTime = info.getLong("respawn_time"); + addKillId(FAFURION_STAGE_1, FAFURION_STAGE_2, FAFURION_STAGE_3, FAFURION_STAGE_4, FAFURION_STAGE_5, FAFURION_STAGE_6, FAFURION_STAGE_7); // Unlock - if (getStatus() == DEAD) + final StatSet info = GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID); + final int status = GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); + if (status == DEAD) { - final long time = respawnTime - System.currentTimeMillis(); + final long time = info.getLong("respawn_time") - System.currentTimeMillis(); if (time > 0) { startQuestTimer("unlock_fafurion", time, null, null); } else { - setStatus(ALIVE); + final GrandBossInstance fafurion = (GrandBossInstance) addSpawn(FAFURION_GRANDBOSS_ID, -113360, -244676, -15536, 0, false, 0); + GrandBossManager.getInstance().addBoss(fafurion); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); } } - else if (getStatus() != ALIVE) + else { - setStatus(ALIVE); + final GrandBossInstance fafurion = (GrandBossInstance) addSpawn(FAFURION_GRANDBOSS_ID, -113360, -244676, -15536, 0, false, 0); + GrandBossManager.getInstance().addBoss(fafurion); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); } } @Override public String onAdvEvent(String event, Npc npc, PlayerInstance player) { - final String htmltext = null; + String htmltext = null; switch (event) { case "unlock_fafurion": { - setStatus(ALIVE); + final GrandBossInstance fafurion = (GrandBossInstance) addSpawn(FAFURION_GRANDBOSS_ID, -113360, -244676, -15536, 0, false, 0); + GrandBossManager.getInstance().addBoss(fafurion); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); break; } case "warning": @@ -111,106 +131,94 @@ public class Fafurion extends AbstractNpcAI } case "beginning": { - if (getStatus() == WAITING) + if (GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID) == WAITING) { - setStatus(FIGHTING); - final Npc bossInstance = addSpawn(FAFURION_FINAL_FORM, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); - startQuestTimer("resetRaid", RAID_DURATION * 60 * 60 * 1000, bossInstance, null); - } - break; - } - case "SKIP_WAITING": - { - if (getStatus() == WAITING) - { - cancelQuestTimer("warning", null, null); - cancelQuestTimer("beginning", null, null); - notifyEvent("beginning", null, null); - player.sendMessage(getClass().getSimpleName() + ": Skipping waiting time ..."); - } - else - { - player.sendMessage(getClass().getSimpleName() + ": You can't skip waiting time right now!"); - } - break; - } - case "RESPAWN_FAFURION": - { - if (getStatus() == DEAD) - { - setRespawn(0); - cancelQuestTimer("unlock_fafurion", null, null); - notifyEvent("unlock_fafurion", null, null); - player.sendMessage(getClass().getSimpleName() + ": Fafurion has been respawned."); - } - else - { - player.sendMessage(getClass().getSimpleName() + ": You can't respawn Fafurion while he is alive!"); - } - break; - } - case "ABORT_FIGHT": - { - if (getStatus() == FIGHTING) - { - setStatus(ALIVE); - cancelQuestTimer("resetRaid", npc, null); - for (Creature creature : zone.getCharactersInside()) + // checking fafurion stage. + _stage = GlobalVariablesManager.getInstance().getInt("Fafurion_Stage", 1); + FAFURION_ZONE.getPlayersInside().forEach(p -> { - if (creature != null) + playMovie(p, Movie.SC_FAFURION_INTRO); + }); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, FIGHTING); + switch (_stage) + { + case 1: { - if (creature.isNpc()) - { - if (creature.getId() == FAFURION_FINAL_FORM) - { - creature.teleToLocation(FAFURION_SPAWN_LOC); - } - else - { - creature.deleteMe(); - } - } - else if (creature.isPlayer() && !creature.isGM()) - { - creature.teleToLocation(ENTER_NPC_LOC); - } + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_1, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 2: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_2, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 3: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_3, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 4: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_4, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 5: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_5, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 6: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_6, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 7: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_7, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; } } - player.sendMessage(getClass().getSimpleName() + ": Fight has been aborted!"); - } - else - { - player.sendMessage(getClass().getSimpleName() + ": You can't abort fight right now!"); + startQuestTimer("resetRaid", RAID_DURATION * 60 * 60 * 1000, _fafurion, null); } break; } case "resetRaid": { - if ((getStatus() > ALIVE) && (getStatus() < DEAD)) + final int status = GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); + if ((status > ALIVE) && (status < DEAD)) { for (PlayerInstance plr : World.getInstance().getVisibleObjectsInRange(npc, PlayerInstance.class, 5000)) { plr.sendPacket(new ExShowScreenMessage(NpcStringId.EXCEEDED_THE_FAFURION_S_NEST_RAID_TIME_LIMIT, ExShowScreenMessage.TOP_CENTER, 10000, true)); } - setStatus(ALIVE); - setRespawn(0); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); + FAFURION_ZONE.oustAllPlayers(); npc.deleteMe(); - + if (_stage > 1) + { + _stage--; + } + GlobalVariablesManager.getInstance().set("Fafurion_Stage", _stage); } break; } case "enter_area": { + final int status = GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); if (player.isGM()) { player.teleToLocation(RAID_ENTER_LOC, true); } else { - if (((getStatus() > ALIVE) && (getStatus() < DEAD)) || (getStatus() == DEAD)) + if (((status > ALIVE) && (status < DEAD)) || (status == DEAD)) { return "34488-02.html"; } + if (FAFURION_ZONE.getPlayersInside().size() >= MAX_PEOPLE) + { + return "34488-03.html"; + } if (!player.isInParty()) { return "34488-01.html"; @@ -227,6 +235,10 @@ public class Fafurion extends AbstractNpcAI { return "34488-01.html"; } + if (members.size() > (MAX_PEOPLE - FAFURION_ZONE.getPlayersInside().size())) + { + return "34488-03.html"; + } for (PlayerInstance member : members) { if (member.getLevel() < Config.FAFURION_MIN_PLAYER_LVL) @@ -249,9 +261,9 @@ public class Fafurion extends AbstractNpcAI } } } - if (getStatus() == ALIVE) + if (status == ALIVE) { - setStatus(WAITING); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, WAITING); startQuestTimer("beginning", Config.FAFURION_WAIT_TIME * 60000, null, null); startQuestTimer("warning", Config.FAFURION_WAIT_TIME > 0 ? (Config.FAFURION_WAIT_TIME * 60000) - 30000 : 0, null, player); } @@ -261,36 +273,195 @@ public class Fafurion extends AbstractNpcAI return htmltext; } + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + if (npc.getId() == _fafurion.getId()) + { + switch (npc.getId()) + { + // TODO: Manage Rage and feature do decrease rage in rooms. + case FAFURION_STAGE_1: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + break; + } + case FAFURION_STAGE_2: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + break; + } + case FAFURION_STAGE_3: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_4: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_5: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_6: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_7: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + @Override public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) { - for (PlayerInstance player : World.getInstance().getVisibleObjectsInRange(npc, PlayerInstance.class, 5000)) + if (npc.getId() == _fafurion.getId()) { - player.sendPacket(new ExShowScreenMessage(NpcStringId.HONORED_WARRIORS_HAVE_DEFEATED_THE_WATER_DRAGON_FAFURION, ExShowScreenMessage.TOP_CENTER, 10000, true)); + FAFURION_ZONE.getPlayersInside().forEach(p -> + { + playMovie(p, Movie.SC_FAFURION_ENDING); + FAFURION_ZONE.getCharactersInside().forEach(m -> + { + if (m.isMonster()) + { + m.deleteMe(); + } + }); + p.sendPacket(new ExShowScreenMessage(NpcStringId.HONORED_WARRIORS_HAVE_DEFEATED_THE_WATER_DRAGON_FAFURION, ExShowScreenMessage.TOP_CENTER, 20000, true)); + }); + + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, DEAD); + final long respawnTime = (Config.FAFURION_SPAWN_INTERVAL + getRandom(-Config.FAFURION_SPAWN_RANDOM, Config.FAFURION_SPAWN_RANDOM)) * 3600000; + final StatSet info = GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID); + info.set("respawn_time", System.currentTimeMillis() + respawnTime); + GrandBossManager.getInstance().setStatSet(FAFURION_GRANDBOSS_ID, info); + startQuestTimer("unlock_fafurion", respawnTime, null, null); + if (_stage < 7) + { + _stage++; + } + GlobalVariablesManager.getInstance().set("Fafurion_Stage", _stage); } - setStatus(DEAD); - final long respawnTime = (Config.FAFURION_SPAWN_INTERVAL + getRandom(-Config.FAFURION_SPAWN_RANDOM, Config.FAFURION_SPAWN_RANDOM)) * 3600000; - startQuestTimer("unlock_fafurion", respawnTime, null, null); - setRespawn(respawnTime); return super.onKill(npc, killer, isSummon); } - private int getStatus() - { - return GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); - } - - private void setStatus(int status) - { - GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, status); - } - - private void setRespawn(long respawnTime) - { - GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID).set("respawn_time", System.currentTimeMillis() + respawnTime); - } - @Override public String onFirstTalk(Npc npc, PlayerInstance player) { @@ -301,4 +472,4 @@ public class Fafurion extends AbstractNpcAI { new Fafurion(); } -} +} \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/FafurionBoss.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/FafurionBoss.java new file mode 100644 index 0000000000..0e9e4a18c7 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/bosses/Fafurion/FafurionBoss.java @@ -0,0 +1,281 @@ +/* + * 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.Fafurion; + +import org.l2jmobius.commons.util.CommonUtil; +import org.l2jmobius.gameserver.model.actor.Creature; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.skills.SkillCaster; +import org.l2jmobius.gameserver.model.variables.NpcVariables; + +import ai.AbstractNpcAI; + +/** + * @author NviX + */ +public class FafurionBoss extends AbstractNpcAI +{ + // NPCs + private static final int FAFURION_STAGE_1 = 29361; + private static final int FAFURION_STAGE_2 = 29362; + private static final int FAFURION_STAGE_3 = 29363; + private static final int FAFURION_STAGE_4 = 29364; + private static final int FAFURION_STAGE_5 = 29365; + private static final int FAFURION_STAGE_6 = 29366; + private static final int FAFURION_STAGE_7 = 29367; + // Skills + private static final SkillHolder FAFURION_NORMAL_ATTACK = new SkillHolder(32705, 1); + private static final SkillHolder FAFURION_BITE = new SkillHolder(32706, 1); + private static final SkillHolder FAFURION_WATER_BLAST = new SkillHolder(32708, 1); + private static final SkillHolder FAFURION_WATER_SPIRAL = new SkillHolder(32709, 1); + private static final SkillHolder FAFURION_HYDRO_BLAST = new SkillHolder(32711, 1); + private static final SkillHolder FAFURION_HYDRO_SPIRAL = new SkillHolder(32712, 1); + private static final SkillHolder FAFURION_TAIL_STRIKE_1 = new SkillHolder(32713, 1); + private static final SkillHolder FAFURION_TAIL_STRIKE_2 = new SkillHolder(32714, 1); + private static final SkillHolder FAFURION_WATER_WAVE = new SkillHolder(32715, 1); + private static final SkillHolder FAFURION_BREATH = new SkillHolder(32716, 1); + private static final SkillHolder FAFURION_FEAR = new SkillHolder(32717, 1); + private static final SkillHolder FAFURION_TIDAL_WAVE = new SkillHolder(32723, 1); + + private FafurionBoss() + { + registerMobs(FAFURION_STAGE_1, FAFURION_STAGE_2, FAFURION_STAGE_3, FAFURION_STAGE_4, FAFURION_STAGE_5, FAFURION_STAGE_6, FAFURION_STAGE_7); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + switch (event) + { + case "MANAGE_SKILLS": + { + if (npc != null) + { + manageSkills(npc); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + if ((npc.getId() == FAFURION_STAGE_1) || (npc.getId() == FAFURION_STAGE_2) || (npc.getId() == FAFURION_STAGE_3) || (npc.getId() == FAFURION_STAGE_4) || (npc.getId() == FAFURION_STAGE_5) || (npc.getId() == FAFURION_STAGE_6) || (npc.getId() == FAFURION_STAGE_7)) + { + if (skill == null) + { + refreshAiParams(attacker, npc, (damage * 1000)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.25)) + { + refreshAiParams(attacker, npc, ((damage / 3) * 100)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) + { + refreshAiParams(attacker, npc, (damage * 20)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.75)) + { + refreshAiParams(attacker, npc, (damage * 10)); + } + else + { + refreshAiParams(attacker, npc, ((damage / 3) * 20)); + } + manageSkills(npc); + } + + return super.onAttack(npc, attacker, damage, isSummon); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage) + { + refreshAiParams(attacker, npc, damage, damage); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage, int aggro) + { + final int newAggroVal = damage + getRandom(3000); + final int aggroVal = aggro + 1000; + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + if (attacker == vars.getObject("c_quest" + i, Creature.class)) + { + if (vars.getInt("i_quest" + i) < aggroVal) + { + vars.set("i_quest" + i, newAggroVal); + } + return; + } + } + final int index = CommonUtil.getIndexOfMinValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + vars.set("i_quest" + index, newAggroVal); + vars.set("c_quest" + index, attacker); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + startQuestTimer("MANAGE_SKILLS", 1000, npc, null); + return super.onSpellFinished(npc, player, skill); + } + + private void manageSkills(Npc npc) + { + if (npc.isCastingNow(SkillCaster::isAnyNormalType) || npc.isCoreAIDisabled() || !npc.isInCombat()) + { + return; + } + + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + final Creature attacker = vars.getObject("c_quest" + i, Creature.class); + if ((attacker == null) || ((npc.calculateDistance3D(attacker) > 9000) || attacker.isDead())) + { + vars.set("i_quest" + i, 0); + } + } + final int index = CommonUtil.getIndexOfMaxValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + final Creature player = vars.getObject("c_quest" + index, Creature.class); + final int i2 = vars.getInt("i_quest" + index); + if ((i2 > 0) && (getRandom(100) < 70)) + { + vars.set("i_quest" + index, 500); + } + + SkillHolder skillToCast = null; + if ((player != null) && !player.isDead()) + { + int chance = getRandom(100); + if (npc.getCurrentHp() > (npc.getMaxHp() * 0.8)) + { + if (chance < 30) + { + skillToCast = FAFURION_WATER_BLAST; + } + else if (chance < 40) + { + skillToCast = FAFURION_FEAR; + } + else if (chance < 60) + { + skillToCast = FAFURION_BREATH; + } + else + { + skillToCast = FAFURION_NORMAL_ATTACK; + } + } + else if (npc.getCurrentHp() > (npc.getMaxHp() * 0.6)) + { + if (chance < 15) + { + skillToCast = FAFURION_WATER_BLAST; + } + else if (chance < 10) + { + skillToCast = FAFURION_FEAR; + } + else if (chance < 35) + { + skillToCast = FAFURION_BREATH; + } + else if (chance < 50) + { + skillToCast = FAFURION_TAIL_STRIKE_1; + } + else if (chance < 65) + { + skillToCast = FAFURION_TAIL_STRIKE_2; + } + else + { + skillToCast = FAFURION_NORMAL_ATTACK; + } + } + else if (npc.getCurrentHp() > (npc.getMaxHp() * 0.3)) + { + if (chance < 5) + { + skillToCast = FAFURION_WATER_BLAST; + } + else if (chance < 10) + { + skillToCast = FAFURION_FEAR; + } + else if (chance < 15) + { + skillToCast = FAFURION_BREATH; + } + else if (chance < 20) + { + skillToCast = FAFURION_TAIL_STRIKE_1; + } + else if (chance < 30) + { + skillToCast = FAFURION_TAIL_STRIKE_2; + } + else if (chance < 40) + { + skillToCast = FAFURION_BITE; + } + else if (chance < 50) + { + skillToCast = FAFURION_WATER_SPIRAL; + } + else if (chance < 60) + { + skillToCast = FAFURION_HYDRO_BLAST; + } + else if (chance < 70) + { + skillToCast = FAFURION_HYDRO_SPIRAL; + } + else if (chance < 80) + { + skillToCast = FAFURION_WATER_WAVE; + } + else if (chance < 90) + { + skillToCast = FAFURION_TIDAL_WAVE; + } + else + { + skillToCast = FAFURION_NORMAL_ATTACK; + } + } + } + + if ((skillToCast != null) && SkillCaster.checkUseConditions(npc, skillToCast.getSkill())) + { + npc.setTarget(player); + npc.doCast(skillToCast.getSkill()); + } + } + + public static void main(String[] args) + { + new FafurionBoss(); + } +} diff --git a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/enums/Movie.java b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/enums/Movie.java index 1d6372ae4f..a45116d2c4 100644 --- a/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/enums/Movie.java +++ b/L2J_Mobius_6.0_Fafurion/java/org/l2jmobius/gameserver/enums/Movie.java @@ -142,6 +142,8 @@ public enum Movie SC_INZONE_KAIN_INTRO(147, true), SC_INZONE_HELIOS_TRANS_A(148, true), SC_INZONE_HELIOS_TRANS_B(149, true), + SC_FAFURION_INTRO(150, true), + SC_FAFURION_ENDING(151, true), LAND_KSERTH_A(1000, true), LAND_KSERTH_B(1001, true), LAND_UNDEAD_A(1002, true), diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/34488-03.html b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/34488-03.html new file mode 100644 index 0000000000..0e8ca33ac7 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/34488-03.html @@ -0,0 +1,5 @@ +Heart of Tsunami:
+(A thundering voice speaks in your head.)
+Maximum of 200 player can enter.
+(You cannot challenge Fafurion at this time.)
+ \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/EliteWizard.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/EliteWizard.java new file mode 100644 index 0000000000..4658164ce3 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/EliteWizard.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.Fafurion; + +import org.l2jmobius.commons.util.CommonUtil; +import org.l2jmobius.gameserver.model.actor.Creature; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.skills.SkillCaster; +import org.l2jmobius.gameserver.model.variables.NpcVariables; + +import ai.AbstractNpcAI; + +/** + * @author NviX + */ +public class EliteWizard extends AbstractNpcAI +{ + // Npc + private static final int ELITE_WIZARD = 29373; + // Skills + private static final SkillHolder WATER_ARROW = new SkillHolder(32740, 1); + private static final SkillHolder ARROW_FLUSH = new SkillHolder(32741, 1); + + private EliteWizard() + { + registerMobs(ELITE_WIZARD); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + switch (event) + { + case "MANAGE_SKILLS": + { + if (npc != null) + { + manageSkills(npc); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + if (npc.getId() == ELITE_WIZARD) + { + if (skill == null) + { + refreshAiParams(attacker, npc, (damage * 1000)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.25)) + { + refreshAiParams(attacker, npc, ((damage / 3) * 100)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) + { + refreshAiParams(attacker, npc, (damage * 20)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.75)) + { + refreshAiParams(attacker, npc, (damage * 10)); + } + else + { + refreshAiParams(attacker, npc, ((damage / 3) * 20)); + } + manageSkills(npc); + } + + return super.onAttack(npc, attacker, damage, isSummon); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage) + { + refreshAiParams(attacker, npc, damage, damage); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage, int aggro) + { + final int newAggroVal = damage + getRandom(3000); + final int aggroVal = aggro + 1000; + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + if (attacker == vars.getObject("c_quest" + i, Creature.class)) + { + if (vars.getInt("i_quest" + i) < aggroVal) + { + vars.set("i_quest" + i, newAggroVal); + } + return; + } + } + final int index = CommonUtil.getIndexOfMinValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + vars.set("i_quest" + index, newAggroVal); + vars.set("c_quest" + index, attacker); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + startQuestTimer("MANAGE_SKILLS", 1000, npc, null); + return super.onSpellFinished(npc, player, skill); + } + + private void manageSkills(Npc npc) + { + if (npc.isCastingNow(SkillCaster::isAnyNormalType) || npc.isCoreAIDisabled() || !npc.isInCombat()) + { + return; + } + + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + final Creature attacker = vars.getObject("c_quest" + i, Creature.class); + if ((attacker == null) || ((npc.calculateDistance3D(attacker) > 9000) || attacker.isDead())) + { + vars.set("i_quest" + i, 0); + } + } + final int index = CommonUtil.getIndexOfMaxValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + final Creature player = vars.getObject("c_quest" + index, Creature.class); + final int i2 = vars.getInt("i_quest" + index); + if ((i2 > 0) && (getRandom(100) < 70)) + { + vars.set("i_quest" + index, 500); + } + + SkillHolder skillToCast = null; + if ((player != null) && !player.isDead()) + { + if (getRandom(100) < 30) + { + skillToCast = ARROW_FLUSH; + } + else + { + skillToCast = WATER_ARROW; + } + } + + if ((skillToCast != null) && SkillCaster.checkUseConditions(npc, skillToCast.getSkill())) + { + npc.setTarget(player); + npc.doCast(skillToCast.getSkill()); + } + } + + public static void main(String[] args) + { + new EliteWizard(); + } +} diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java index 772cef0b57..356974ddd9 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/Fafurion.java @@ -14,19 +14,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package ai.bosses.Fafurion; import java.util.List; import org.l2jmobius.Config; +import org.l2jmobius.gameserver.enums.Movie; +import org.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; import org.l2jmobius.gameserver.instancemanager.GrandBossManager; import org.l2jmobius.gameserver.instancemanager.ZoneManager; import org.l2jmobius.gameserver.model.Location; import org.l2jmobius.gameserver.model.Party; import org.l2jmobius.gameserver.model.StatSet; import org.l2jmobius.gameserver.model.World; -import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.GrandBossInstance; import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; import org.l2jmobius.gameserver.model.zone.type.NoRestartZone; import org.l2jmobius.gameserver.network.NpcStringId; @@ -42,59 +45,76 @@ public class Fafurion extends AbstractNpcAI // NPCs private static final int HEART_OF_TSUNAMI = 34488; private static final int FAFURION_GRANDBOSS_ID = 19740; - private static final int FAFURION_FINAL_FORM = 29367; + private static final int FAFURION_STAGE_1 = 29361; + private static final int FAFURION_STAGE_2 = 29362; + private static final int FAFURION_STAGE_3 = 29363; + private static final int FAFURION_STAGE_4 = 29364; + private static final int FAFURION_STAGE_5 = 29365; + private static final int FAFURION_STAGE_6 = 29366; + private static final int FAFURION_STAGE_7 = 29367; + private static final int EMERALD_DRAGON = 29368; + private static final int BLUE_WATER_DRAGON = 29369; + private static final int FAFURION_DEFENDER = 29370; // Item private static final int FONDUS_STONE = 80322; + // Zone + private static final NoRestartZone FAFURION_ZONE = ZoneManager.getInstance().getZoneById(85002, NoRestartZone.class); // Locations - private static final Location ENTER_NPC_LOC = new Location(190856, 257112, -3328); private static final Location RAID_ENTER_LOC = new Location(180059, 212896, -14727); private static final Location FAFURION_SPAWN_LOC = new Location(180712, 210664, -14823, 22146); - // Zone - private static final NoRestartZone zone = ZoneManager.getInstance().getZoneById(85002, NoRestartZone.class); // Fafurion Nest zone // Status private static final int ALIVE = 0; private static final int WAITING = 1; private static final int FIGHTING = 2; private static final int DEAD = 3; // Misc + private static final int MAX_PEOPLE = 200; private static final int RAID_DURATION = 5; // hours + private static GrandBossInstance _fafurion; + private int _stage; private Fafurion() { addStartNpc(HEART_OF_TSUNAMI); addTalkId(HEART_OF_TSUNAMI); addFirstTalkId(HEART_OF_TSUNAMI); - addKillId(FAFURION_FINAL_FORM); - final StatSet info = GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID); - final long respawnTime = info.getLong("respawn_time"); + addKillId(FAFURION_STAGE_1, FAFURION_STAGE_2, FAFURION_STAGE_3, FAFURION_STAGE_4, FAFURION_STAGE_5, FAFURION_STAGE_6, FAFURION_STAGE_7); // Unlock - if (getStatus() == DEAD) + final StatSet info = GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID); + final int status = GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); + if (status == DEAD) { - final long time = respawnTime - System.currentTimeMillis(); + final long time = info.getLong("respawn_time") - System.currentTimeMillis(); if (time > 0) { startQuestTimer("unlock_fafurion", time, null, null); } else { - setStatus(ALIVE); + final GrandBossInstance fafurion = (GrandBossInstance) addSpawn(FAFURION_GRANDBOSS_ID, -113360, -244676, -15536, 0, false, 0); + GrandBossManager.getInstance().addBoss(fafurion); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); } } - else if (getStatus() != ALIVE) + else { - setStatus(ALIVE); + final GrandBossInstance fafurion = (GrandBossInstance) addSpawn(FAFURION_GRANDBOSS_ID, -113360, -244676, -15536, 0, false, 0); + GrandBossManager.getInstance().addBoss(fafurion); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); } } @Override public String onAdvEvent(String event, Npc npc, PlayerInstance player) { - final String htmltext = null; + String htmltext = null; switch (event) { case "unlock_fafurion": { - setStatus(ALIVE); + final GrandBossInstance fafurion = (GrandBossInstance) addSpawn(FAFURION_GRANDBOSS_ID, -113360, -244676, -15536, 0, false, 0); + GrandBossManager.getInstance().addBoss(fafurion); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); break; } case "warning": @@ -111,106 +131,94 @@ public class Fafurion extends AbstractNpcAI } case "beginning": { - if (getStatus() == WAITING) + if (GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID) == WAITING) { - setStatus(FIGHTING); - final Npc bossInstance = addSpawn(FAFURION_FINAL_FORM, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); - startQuestTimer("resetRaid", RAID_DURATION * 60 * 60 * 1000, bossInstance, null); - } - break; - } - case "SKIP_WAITING": - { - if (getStatus() == WAITING) - { - cancelQuestTimer("warning", null, null); - cancelQuestTimer("beginning", null, null); - notifyEvent("beginning", null, null); - player.sendMessage(getClass().getSimpleName() + ": Skipping waiting time ..."); - } - else - { - player.sendMessage(getClass().getSimpleName() + ": You can't skip waiting time right now!"); - } - break; - } - case "RESPAWN_FAFURION": - { - if (getStatus() == DEAD) - { - setRespawn(0); - cancelQuestTimer("unlock_fafurion", null, null); - notifyEvent("unlock_fafurion", null, null); - player.sendMessage(getClass().getSimpleName() + ": Fafurion has been respawned."); - } - else - { - player.sendMessage(getClass().getSimpleName() + ": You can't respawn Fafurion while he is alive!"); - } - break; - } - case "ABORT_FIGHT": - { - if (getStatus() == FIGHTING) - { - setStatus(ALIVE); - cancelQuestTimer("resetRaid", npc, null); - for (Creature creature : zone.getCharactersInside()) + // checking fafurion stage. + _stage = GlobalVariablesManager.getInstance().getInt("Fafurion_Stage", 1); + FAFURION_ZONE.getPlayersInside().forEach(p -> { - if (creature != null) + playMovie(p, Movie.SC_FAFURION_INTRO); + }); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, FIGHTING); + switch (_stage) + { + case 1: { - if (creature.isNpc()) - { - if (creature.getId() == FAFURION_FINAL_FORM) - { - creature.teleToLocation(FAFURION_SPAWN_LOC); - } - else - { - creature.deleteMe(); - } - } - else if (creature.isPlayer() && !creature.isGM()) - { - creature.teleToLocation(ENTER_NPC_LOC); - } + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_1, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 2: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_2, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 3: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_3, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 4: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_4, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 5: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_5, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 6: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_6, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; + } + case 7: + { + _fafurion = (GrandBossInstance) addSpawn(FAFURION_STAGE_7, FAFURION_SPAWN_LOC.getX(), FAFURION_SPAWN_LOC.getY(), FAFURION_SPAWN_LOC.getZ(), FAFURION_SPAWN_LOC.getHeading(), false, 0, false); + break; } } - player.sendMessage(getClass().getSimpleName() + ": Fight has been aborted!"); - } - else - { - player.sendMessage(getClass().getSimpleName() + ": You can't abort fight right now!"); + startQuestTimer("resetRaid", RAID_DURATION * 60 * 60 * 1000, _fafurion, null); } break; } case "resetRaid": { - if ((getStatus() > ALIVE) && (getStatus() < DEAD)) + final int status = GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); + if ((status > ALIVE) && (status < DEAD)) { for (PlayerInstance plr : World.getInstance().getVisibleObjectsInRange(npc, PlayerInstance.class, 5000)) { plr.sendPacket(new ExShowScreenMessage(NpcStringId.EXCEEDED_THE_FAFURION_S_NEST_RAID_TIME_LIMIT, ExShowScreenMessage.TOP_CENTER, 10000, true)); } - setStatus(ALIVE); - setRespawn(0); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, ALIVE); + FAFURION_ZONE.oustAllPlayers(); npc.deleteMe(); - + if (_stage > 1) + { + _stage--; + } + GlobalVariablesManager.getInstance().set("Fafurion_Stage", _stage); } break; } case "enter_area": { + final int status = GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); if (player.isGM()) { player.teleToLocation(RAID_ENTER_LOC, true); } else { - if (((getStatus() > ALIVE) && (getStatus() < DEAD)) || (getStatus() == DEAD)) + if (((status > ALIVE) && (status < DEAD)) || (status == DEAD)) { return "34488-02.html"; } + if (FAFURION_ZONE.getPlayersInside().size() >= MAX_PEOPLE) + { + return "34488-03.html"; + } if (!player.isInParty()) { return "34488-01.html"; @@ -227,6 +235,10 @@ public class Fafurion extends AbstractNpcAI { return "34488-01.html"; } + if (members.size() > (MAX_PEOPLE - FAFURION_ZONE.getPlayersInside().size())) + { + return "34488-03.html"; + } for (PlayerInstance member : members) { if (member.getLevel() < Config.FAFURION_MIN_PLAYER_LVL) @@ -249,9 +261,9 @@ public class Fafurion extends AbstractNpcAI } } } - if (getStatus() == ALIVE) + if (status == ALIVE) { - setStatus(WAITING); + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, WAITING); startQuestTimer("beginning", Config.FAFURION_WAIT_TIME * 60000, null, null); startQuestTimer("warning", Config.FAFURION_WAIT_TIME > 0 ? (Config.FAFURION_WAIT_TIME * 60000) - 30000 : 0, null, player); } @@ -261,36 +273,195 @@ public class Fafurion extends AbstractNpcAI return htmltext; } + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + if (npc.getId() == _fafurion.getId()) + { + switch (npc.getId()) + { + // TODO: Manage Rage and feature do decrease rage in rooms. + case FAFURION_STAGE_1: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + break; + } + case FAFURION_STAGE_2: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + break; + } + case FAFURION_STAGE_3: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_4: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_5: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 3; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_6: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + case FAFURION_STAGE_7: + { + if (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.3)) + { + for (int i = 1; i < 4; i++) + { + addSpawn(EMERALD_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(BLUE_WATER_DRAGON, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + addSpawn(FAFURION_DEFENDER, npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), true, 0); + } + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + @Override public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) { - for (PlayerInstance player : World.getInstance().getVisibleObjectsInRange(npc, PlayerInstance.class, 5000)) + if (npc.getId() == _fafurion.getId()) { - player.sendPacket(new ExShowScreenMessage(NpcStringId.HONORED_WARRIORS_HAVE_DEFEATED_THE_WATER_DRAGON_FAFURION, ExShowScreenMessage.TOP_CENTER, 10000, true)); + FAFURION_ZONE.getPlayersInside().forEach(p -> + { + playMovie(p, Movie.SC_FAFURION_ENDING); + FAFURION_ZONE.getCharactersInside().forEach(m -> + { + if (m.isMonster()) + { + m.deleteMe(); + } + }); + p.sendPacket(new ExShowScreenMessage(NpcStringId.HONORED_WARRIORS_HAVE_DEFEATED_THE_WATER_DRAGON_FAFURION, ExShowScreenMessage.TOP_CENTER, 20000, true)); + }); + + GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, DEAD); + final long respawnTime = (Config.FAFURION_SPAWN_INTERVAL + getRandom(-Config.FAFURION_SPAWN_RANDOM, Config.FAFURION_SPAWN_RANDOM)) * 3600000; + final StatSet info = GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID); + info.set("respawn_time", System.currentTimeMillis() + respawnTime); + GrandBossManager.getInstance().setStatSet(FAFURION_GRANDBOSS_ID, info); + startQuestTimer("unlock_fafurion", respawnTime, null, null); + if (_stage < 7) + { + _stage++; + } + GlobalVariablesManager.getInstance().set("Fafurion_Stage", _stage); } - setStatus(DEAD); - final long respawnTime = (Config.FAFURION_SPAWN_INTERVAL + getRandom(-Config.FAFURION_SPAWN_RANDOM, Config.FAFURION_SPAWN_RANDOM)) * 3600000; - startQuestTimer("unlock_fafurion", respawnTime, null, null); - setRespawn(respawnTime); return super.onKill(npc, killer, isSummon); } - private int getStatus() - { - return GrandBossManager.getInstance().getBossStatus(FAFURION_GRANDBOSS_ID); - } - - private void setStatus(int status) - { - GrandBossManager.getInstance().setBossStatus(FAFURION_GRANDBOSS_ID, status); - } - - private void setRespawn(long respawnTime) - { - GrandBossManager.getInstance().getStatSet(FAFURION_GRANDBOSS_ID).set("respawn_time", System.currentTimeMillis() + respawnTime); - } - @Override public String onFirstTalk(Npc npc, PlayerInstance player) { @@ -301,4 +472,4 @@ public class Fafurion extends AbstractNpcAI { new Fafurion(); } -} +} \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/FafurionBoss.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/FafurionBoss.java new file mode 100644 index 0000000000..0e9e4a18c7 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/bosses/Fafurion/FafurionBoss.java @@ -0,0 +1,281 @@ +/* + * 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.Fafurion; + +import org.l2jmobius.commons.util.CommonUtil; +import org.l2jmobius.gameserver.model.actor.Creature; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.skills.SkillCaster; +import org.l2jmobius.gameserver.model.variables.NpcVariables; + +import ai.AbstractNpcAI; + +/** + * @author NviX + */ +public class FafurionBoss extends AbstractNpcAI +{ + // NPCs + private static final int FAFURION_STAGE_1 = 29361; + private static final int FAFURION_STAGE_2 = 29362; + private static final int FAFURION_STAGE_3 = 29363; + private static final int FAFURION_STAGE_4 = 29364; + private static final int FAFURION_STAGE_5 = 29365; + private static final int FAFURION_STAGE_6 = 29366; + private static final int FAFURION_STAGE_7 = 29367; + // Skills + private static final SkillHolder FAFURION_NORMAL_ATTACK = new SkillHolder(32705, 1); + private static final SkillHolder FAFURION_BITE = new SkillHolder(32706, 1); + private static final SkillHolder FAFURION_WATER_BLAST = new SkillHolder(32708, 1); + private static final SkillHolder FAFURION_WATER_SPIRAL = new SkillHolder(32709, 1); + private static final SkillHolder FAFURION_HYDRO_BLAST = new SkillHolder(32711, 1); + private static final SkillHolder FAFURION_HYDRO_SPIRAL = new SkillHolder(32712, 1); + private static final SkillHolder FAFURION_TAIL_STRIKE_1 = new SkillHolder(32713, 1); + private static final SkillHolder FAFURION_TAIL_STRIKE_2 = new SkillHolder(32714, 1); + private static final SkillHolder FAFURION_WATER_WAVE = new SkillHolder(32715, 1); + private static final SkillHolder FAFURION_BREATH = new SkillHolder(32716, 1); + private static final SkillHolder FAFURION_FEAR = new SkillHolder(32717, 1); + private static final SkillHolder FAFURION_TIDAL_WAVE = new SkillHolder(32723, 1); + + private FafurionBoss() + { + registerMobs(FAFURION_STAGE_1, FAFURION_STAGE_2, FAFURION_STAGE_3, FAFURION_STAGE_4, FAFURION_STAGE_5, FAFURION_STAGE_6, FAFURION_STAGE_7); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + switch (event) + { + case "MANAGE_SKILLS": + { + if (npc != null) + { + manageSkills(npc); + } + break; + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + if ((npc.getId() == FAFURION_STAGE_1) || (npc.getId() == FAFURION_STAGE_2) || (npc.getId() == FAFURION_STAGE_3) || (npc.getId() == FAFURION_STAGE_4) || (npc.getId() == FAFURION_STAGE_5) || (npc.getId() == FAFURION_STAGE_6) || (npc.getId() == FAFURION_STAGE_7)) + { + if (skill == null) + { + refreshAiParams(attacker, npc, (damage * 1000)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.25)) + { + refreshAiParams(attacker, npc, ((damage / 3) * 100)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.5)) + { + refreshAiParams(attacker, npc, (damage * 20)); + } + else if (npc.getCurrentHp() < (npc.getMaxHp() * 0.75)) + { + refreshAiParams(attacker, npc, (damage * 10)); + } + else + { + refreshAiParams(attacker, npc, ((damage / 3) * 20)); + } + manageSkills(npc); + } + + return super.onAttack(npc, attacker, damage, isSummon); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage) + { + refreshAiParams(attacker, npc, damage, damage); + } + + private final void refreshAiParams(Creature attacker, Npc npc, int damage, int aggro) + { + final int newAggroVal = damage + getRandom(3000); + final int aggroVal = aggro + 1000; + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + if (attacker == vars.getObject("c_quest" + i, Creature.class)) + { + if (vars.getInt("i_quest" + i) < aggroVal) + { + vars.set("i_quest" + i, newAggroVal); + } + return; + } + } + final int index = CommonUtil.getIndexOfMinValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + vars.set("i_quest" + index, newAggroVal); + vars.set("c_quest" + index, attacker); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + startQuestTimer("MANAGE_SKILLS", 1000, npc, null); + return super.onSpellFinished(npc, player, skill); + } + + private void manageSkills(Npc npc) + { + if (npc.isCastingNow(SkillCaster::isAnyNormalType) || npc.isCoreAIDisabled() || !npc.isInCombat()) + { + return; + } + + final NpcVariables vars = npc.getVariables(); + for (int i = 0; i < 3; i++) + { + final Creature attacker = vars.getObject("c_quest" + i, Creature.class); + if ((attacker == null) || ((npc.calculateDistance3D(attacker) > 9000) || attacker.isDead())) + { + vars.set("i_quest" + i, 0); + } + } + final int index = CommonUtil.getIndexOfMaxValue(vars.getInt("i_quest0"), vars.getInt("i_quest1"), vars.getInt("i_quest2")); + final Creature player = vars.getObject("c_quest" + index, Creature.class); + final int i2 = vars.getInt("i_quest" + index); + if ((i2 > 0) && (getRandom(100) < 70)) + { + vars.set("i_quest" + index, 500); + } + + SkillHolder skillToCast = null; + if ((player != null) && !player.isDead()) + { + int chance = getRandom(100); + if (npc.getCurrentHp() > (npc.getMaxHp() * 0.8)) + { + if (chance < 30) + { + skillToCast = FAFURION_WATER_BLAST; + } + else if (chance < 40) + { + skillToCast = FAFURION_FEAR; + } + else if (chance < 60) + { + skillToCast = FAFURION_BREATH; + } + else + { + skillToCast = FAFURION_NORMAL_ATTACK; + } + } + else if (npc.getCurrentHp() > (npc.getMaxHp() * 0.6)) + { + if (chance < 15) + { + skillToCast = FAFURION_WATER_BLAST; + } + else if (chance < 10) + { + skillToCast = FAFURION_FEAR; + } + else if (chance < 35) + { + skillToCast = FAFURION_BREATH; + } + else if (chance < 50) + { + skillToCast = FAFURION_TAIL_STRIKE_1; + } + else if (chance < 65) + { + skillToCast = FAFURION_TAIL_STRIKE_2; + } + else + { + skillToCast = FAFURION_NORMAL_ATTACK; + } + } + else if (npc.getCurrentHp() > (npc.getMaxHp() * 0.3)) + { + if (chance < 5) + { + skillToCast = FAFURION_WATER_BLAST; + } + else if (chance < 10) + { + skillToCast = FAFURION_FEAR; + } + else if (chance < 15) + { + skillToCast = FAFURION_BREATH; + } + else if (chance < 20) + { + skillToCast = FAFURION_TAIL_STRIKE_1; + } + else if (chance < 30) + { + skillToCast = FAFURION_TAIL_STRIKE_2; + } + else if (chance < 40) + { + skillToCast = FAFURION_BITE; + } + else if (chance < 50) + { + skillToCast = FAFURION_WATER_SPIRAL; + } + else if (chance < 60) + { + skillToCast = FAFURION_HYDRO_BLAST; + } + else if (chance < 70) + { + skillToCast = FAFURION_HYDRO_SPIRAL; + } + else if (chance < 80) + { + skillToCast = FAFURION_WATER_WAVE; + } + else if (chance < 90) + { + skillToCast = FAFURION_TIDAL_WAVE; + } + else + { + skillToCast = FAFURION_NORMAL_ATTACK; + } + } + } + + if ((skillToCast != null) && SkillCaster.checkUseConditions(npc, skillToCast.getSkill())) + { + npc.setTarget(player); + npc.doCast(skillToCast.getSkill()); + } + } + + public static void main(String[] args) + { + new FafurionBoss(); + } +} diff --git a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/enums/Movie.java b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/enums/Movie.java index 1d6372ae4f..a45116d2c4 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/enums/Movie.java +++ b/L2J_Mobius_7.0_PreludeOfWar/java/org/l2jmobius/gameserver/enums/Movie.java @@ -142,6 +142,8 @@ public enum Movie SC_INZONE_KAIN_INTRO(147, true), SC_INZONE_HELIOS_TRANS_A(148, true), SC_INZONE_HELIOS_TRANS_B(149, true), + SC_FAFURION_INTRO(150, true), + SC_FAFURION_ENDING(151, true), LAND_KSERTH_A(1000, true), LAND_KSERTH_B(1001, true), LAND_UNDEAD_A(1002, true),