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 21d278f283..ad4baaf622 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19000-19099.xml index 84e0a9ee1e..925f033325 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/teleportzones.xml index d68c0bd43b..ea67b08743 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 21d278f283..ad4baaf622 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19000-19099.xml index e684733153..43ec23bd28 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_2.5_Underground/dist/game/data/zones/teleportzones.xml index 148fab164c..7c3f8b0806 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 9ca4f105cb..97221d49ac 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19000-19099.xml index e684733153..43ec23bd28 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_3.0_Helios/dist/game/data/zones/teleportzones.xml index bbf62a120d..3d4ff454c9 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml index 8727b0389a..b971a893a6 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/19000-19099.xml index e684733153..43ec23bd28 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/zones/teleportzones.xml index bbf62a120d..3d4ff454c9 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/Routes.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/Routes.xml index 8727b0389a..b971a893a6 100644 --- a/L2J_Mobius_5.0_Salvation/dist/game/data/Routes.xml +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/stats/npcs/19000-19099.xml index e684733153..43ec23bd28 100644 --- a/L2J_Mobius_5.0_Salvation/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_5.0_Salvation/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_5.0_Salvation/dist/game/data/zones/teleportzones.xml index 58d7790d91..417a27bcf4 100644 --- a/L2J_Mobius_5.0_Salvation/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_5.0_Salvation/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/Routes.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/Routes.xml index 8727b0389a..b971a893a6 100644 --- a/L2J_Mobius_5.5_EtinasFate/dist/game/data/Routes.xml +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/stats/npcs/19000-19099.xml index e684733153..43ec23bd28 100644 --- a/L2J_Mobius_5.5_EtinasFate/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_5.5_EtinasFate/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_5.5_EtinasFate/dist/game/data/zones/teleportzones.xml index 58d7790d91..417a27bcf4 100644 --- a/L2J_Mobius_5.5_EtinasFate/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_5.5_EtinasFate/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/Routes.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/Routes.xml index 8727b0389a..b971a893a6 100644 --- a/L2J_Mobius_6.0_Fafurion/dist/game/data/Routes.xml +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/stats/npcs/19000-19099.xml index d1a15f1afa..47a6497a67 100644 --- a/L2J_Mobius_6.0_Fafurion/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_6.0_Fafurion/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_6.0_Fafurion/dist/game/data/zones/teleportzones.xml index 58d7790d91..417a27bcf4 100644 --- a/L2J_Mobius_6.0_Fafurion/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_6.0_Fafurion/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/Routes.xml b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/Routes.xml index 8727b0389a..b971a893a6 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/Routes.xml +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/Routes.xml @@ -2476,6 +2476,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsCoralGarden.xml b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsCoralGarden.xml new file mode 100644 index 0000000000..00ecfbdb7d --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsCoralGarden.xml @@ -0,0 +1,238 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml new file mode 100644 index 0000000000..57900c0c1e --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsEmeraldSquare.xml @@ -0,0 +1,2511 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsSteamCorridor.xml b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsSteamCorridor.xml new file mode 100644 index 0000000000..2f12da9071 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/instances/CrystalCavernsSteamCorridor.xml @@ -0,0 +1,694 @@ + + + + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java new file mode 100644 index 0000000000..35880d0254 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortalToCrystalCaverns.java @@ -0,0 +1,215 @@ +/* + * 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.areas.Parnassus.EntrancePortalToCrystalCaverns; + +import java.util.Calendar; + +import org.l2jmobius.gameserver.instancemanager.QuestManager; +import org.l2jmobius.gameserver.model.StatsSet; +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.PlayerInstance; +import org.l2jmobius.gameserver.model.quest.Quest; +import org.l2jmobius.gameserver.network.serverpackets.OnEventTrigger; + +import ai.AbstractNpcAI; +import instances.CrystalCaverns.CrystalCavernsCoralGarden; +import instances.CrystalCaverns.CrystalCavernsEmeraldSquare; +import instances.CrystalCaverns.CrystalCavernsSteamCorridor; + +/** + * Entrance Portal to Crystal Caverns AI. + * @author St3eT + */ +public class EntrancePortalToCrystalCaverns extends AbstractNpcAI +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + // Misc + private static final int EMERALD_SQUARE_TEMPLATE_ID = 163; + private static final int STEAM_CORRIDOR_TEMPLATE_ID = 164; + private static final int CORAL_GARDEN_TEMPLATE_ID = 165; + private static final int PRISON_ENTRACE_TRIGGER_1 = 24230010; + private static final int PRISON_ENTRACE_TRIGGER_2 = 24230012; + private static final int CAVERNS_ENTRACE_TRIGGER_1 = 24230014; + private static final int CAVERNS_ENTRACE_TRIGGER_2 = 24230016; + private static final int CAVERNS_ENTRACE_TRIGGER_3 = 24230018; + + private EntrancePortalToCrystalCaverns() + { + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(CAVERNS_ENTRACE); + addSpawnId(CAVERNS_ENTRACE); + addSeeCreatureId(CAVERNS_ENTRACE); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + Quest instanceScript = null; + + switch (getCurrentInstanceTemplateId()) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsEmeraldSquare.class.getSimpleName()); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsSteamCorridor.class.getSimpleName()); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + instanceScript = QuestManager.getInstance().getQuest(CrystalCavernsCoralGarden.class.getSimpleName()); + break; + } + } + + if (instanceScript != null) + { + instanceScript.notifyEvent(event, npc, player); + } + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + return "EntrancePortal_" + getCurrentInstanceTemplateId() + ".html"; + } + + @Override + public String onSpawn(Npc npc) + { + getTimers().addRepeatingTimer("LOOP_TIMER", 10000, npc, null); + return super.onSpawn(npc); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + if (event.equals("LOOP_TIMER")) + { + final int currentTemplateId = getCurrentInstanceTemplateId(); + + World.getInstance().forEachVisibleObjectInRange(npc, PlayerInstance.class, 500, p -> + { + updateTriggersForPlayer(player, currentTemplateId); + }); + } + } + + @Override + public String onSeeCreature(Npc npc, Creature creature, boolean isSummon) + { + if (creature.isPlayer()) + { + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_1, true)); + creature.getActingPlayer().sendPacket(new OnEventTrigger(PRISON_ENTRACE_TRIGGER_2, true)); + updateTriggersForPlayer(creature.getActingPlayer(), getCurrentInstanceTemplateId()); + } + return super.onSeeCreature(npc, creature, isSummon); + } + + public void updateTriggersForPlayer(PlayerInstance player, int currentTemplateId) + { + if (player != null) + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, false)); + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, false)); + + switch (currentTemplateId) + { + case EMERALD_SQUARE_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_1, true)); + break; + } + case STEAM_CORRIDOR_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_2, true)); + break; + } + case CORAL_GARDEN_TEMPLATE_ID: + { + player.sendPacket(new OnEventTrigger(CAVERNS_ENTRACE_TRIGGER_3, true)); + break; + } + } + } + } + + public int getCurrentInstanceTemplateId() + { + final int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK); + final int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + int templateId = -1; + + switch (day) + { + case Calendar.MONDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.TUESDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.WEDNESDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.THURSDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + case Calendar.FRIDAY: + { + templateId = (hour < 18) ? CORAL_GARDEN_TEMPLATE_ID : EMERALD_SQUARE_TEMPLATE_ID; + break; + } + case Calendar.SATURDAY: + { + templateId = (hour < 18) ? STEAM_CORRIDOR_TEMPLATE_ID : CORAL_GARDEN_TEMPLATE_ID; + break; + } + case Calendar.SUNDAY: + { + templateId = (hour < 18) ? EMERALD_SQUARE_TEMPLATE_ID : STEAM_CORRIDOR_TEMPLATE_ID; + break; + } + } + return templateId; + } + + public static void main(String[] args) + { + new EntrancePortalToCrystalCaverns(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html new file mode 100644 index 0000000000..6de9f6e4b9 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_163.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Emerald Square.
+ + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html new file mode 100644 index 0000000000..b0d8310c68 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_164.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Steam Corridor.
+ + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html new file mode 100644 index 0000000000..ea7efec129 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/ai/areas/Parnassus/EntrancePortalToCrystalCaverns/EntrancePortal_165.html @@ -0,0 +1,4 @@ +Entrance Portal to Crystal Caverns:
+At this time, you can go into the Coral Garden.
+ + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java new file mode 100644 index 0000000000..21d8f0d1b3 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsCoralGarden.java @@ -0,0 +1,253 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.instancemanager.WalkingManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.Spawn; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.actor.Npc; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Coral Garden instance zone. + * @author St3eT + */ +public class CrystalCavernsCoralGarden extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int MICHAELA_NORMAL = 25799; + private static final int MICHAELA_WISE = 26116; + private static final int MICHAELA_WEALTHY = 26115; + private static final int MICHAELA_ARMED = 26114; + private static final int GOLEM_1 = 19013; // Crystalline Golem + private static final int GOLEM_2 = 19014; // Crystalline Golem + // Location + private static final Location BOSS_LOC = new Location(144307, 220032, -11824); + // Misc + private static final int TEMPLATE_ID = 165; + private static final int BOSS_DOOR_ID = 24240026; + private static final int PLAYER_MAX_DISTANCE = 250; + + public CrystalCavernsCoralGarden() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addFirstTalkId(GOLEM_1, GOLEM_2); + addKillId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addAttackId(MICHAELA_NORMAL, MICHAELA_WISE, MICHAELA_WEALTHY, MICHAELA_ARMED); + addRouteFinishedId(GOLEM_1, GOLEM_2); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "SUCCESS_TIMER": + { + showOnScreenMsg(instance, NpcStringId.GOLEM_LOCATION_SUCCESSFUL_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 5000); + break; + } + case "LOOP_TIMER": + { + player = npcVars.getObject("PLAYER_OBJECT", PlayerInstance.class); + + if ((player != null) && (npc.calculateDistance3D(player) > PLAYER_MAX_DISTANCE) && npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + addMoveToDesire(npc, new Location(npc.getX() + getRandom(-100, 100), npc.getY() + getRandom(-150, 150), npc.getZ()), 23); + npc.setRunning(); + npcVars.set("NPC_FOLLOWING", false); + getTimers().cancelTimer("LOOP_TIMER", npc, null); + getTimers().addTimer("FAIL_TIMER", 5000, npc, null); + } + break; + } + case "FAIL_TIMER": + { + final Spawn spawn = npc.getSpawn(); + + if (!npcVars.getBoolean("NPC_FOLLOWING", true)) + { + WalkingManager.getInstance().cancelMoving(npc); + npc.setWalking(); + npc.teleToLocation(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ()); + npc.setScriptValue(0); + npc.setNameString(null); + npc.setTitleString(null); + npc.setTitle(null); + npc.broadcastInfo(); + } + npcVars.set("CAN_CALL_MONSTERS", ((spawn.getX() - ((npc.getX() * spawn.getX()) - npc.getX())) + (spawn.getY() - (npc.getY() * spawn.getY()) - npc.getY())) > (200 * 200)); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onFirstTalk(Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.getVariables().set("PLAYER_OBJECT", player); + npc.setNameString(NpcStringId.TRAITOR_CRYSTALLINE_GOLEM); + npc.setTitleString(NpcStringId.GIVEN_TO_S1); + npc.setTitle(player.getName()); + npc.broadcastInfo(); + WalkingManager.getInstance().startMoving(npc, npc.getId() == GOLEM_1 ? "gd_golem_1" : "gd_golem_2"); + getTimers().addRepeatingTimer("LOOP_TIMER", 500, npc, null); + } + } + return null; + } + + @Override + public void onRouteFinished(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (instance != null) + { + WalkingManager.getInstance().cancelMoving(npc); + showOnScreenMsg(instance, NpcStringId.GOLEM_ENTERED_THE_REQUIRED_ZONE, ExShowScreenMessage.MIDDLE_CENTER, 5000); + npc.deleteMe(); + + if (instance.getAliveNpcs(GOLEM_1, GOLEM_2).isEmpty()) + { + instance.openCloseDoor(BOSS_DOOR_ID, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = MICHAELA_NORMAL; + } + else if (random < 80) + { + bossId = MICHAELA_WISE; + } + else if (random < 95) + { + bossId = MICHAELA_WEALTHY; + } + else + { + bossId = MICHAELA_ARMED; + } + + final Npc boss = addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + getTimers().addTimer("SUCCESS_TIMER", 5000, boss, null); + } + } + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case MICHAELA_NORMAL: + case MICHAELA_WISE: + case MICHAELA_WEALTHY: + case MICHAELA_ARMED: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + instance.openCloseDoor(BOSS_DOOR_ID, false); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + public static void main(String[] args) + { + new CrystalCavernsCoralGarden(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java new file mode 100644 index 0000000000..26bb4ad5c8 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsEmeraldSquare.java @@ -0,0 +1,424 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +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.MonsterInstance; +import org.l2jmobius.gameserver.model.actor.instance.PlayerInstance; +import org.l2jmobius.gameserver.model.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.skills.Skill; +import org.l2jmobius.gameserver.model.stats.Stats; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Emerald Square instance zone. + * @author St3eT + */ +public class CrystalCavernsEmeraldSquare extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int VERIDAN_NORMAL = 25796; + private static final int VERIDAN_WISE = 26107; + private static final int VERIDAN_WEALTHY = 26106; + private static final int VERIDAN_ARMED = 26105; + private static final int WATER_CANNON = 19008; + private static final int WATER_CANNON_SKILL = 19009; + private static final int STRONGHOLD_PROTECTOR = 23012; + private static final int SQUARE_INTRUDER = 23010; + private static final int SQUARE_ATTACKER = 23011; + // Skills + private static final SkillHolder DESTROY_SKILL = new SkillHolder(12003, 1); + private static final SkillHolder WATER_CANNON_SKILL_ATTACK = new SkillHolder(14179, 1); + // Locations + private static final Location[] BOSS_SPAWNS = + { + new Location(152745, 145957, -12584, 16446), + new Location(152816, 145968, -12633, 16446), + }; + // Misc + private static final int TEMPLATE_ID = 163; + private static final int RAID_DOOR_1 = 24220005; + private static final int RAID_DOOR_2 = 24220006; + + public CrystalCavernsEmeraldSquare() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addSpawnId(WATER_CANNON); + addKillId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addAttackId(WATER_CANNON, VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED); + addSpellFinishedId(WATER_CANNON_SKILL); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, WATER_CANNON); + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final StatsSet npcVars = npc.getVariables(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (event) + { + case "HP_REGEN_TIMER": + { + int value = ((baseId == 5) || (baseId == 6)) ? 5 : baseId; + npc.getStat().addFixedValue(Stats.REGENERATE_HP_RATE, Double.valueOf(value * 1000)); + break; + } + case "SUPPORT_SPAWN_TIMER": + { + int supportVal = npcVars.getInt("SUPPORT_VALUE", 0); + + if (supportVal > 3) + { + return; + } + + if ((supportVal == 0) || (supportVal == 1) || (supportVal == 2)) + { + final String spawnName = npcParams.getString("SupportMaker" + (supportVal + 1), null); + if (spawnName != null) + { + instance.spawnGroup(spawnName); + } + npcVars.increaseInt("SUPPORT_VALUE", 1); + } + + if (!npcVars.getBoolean("PREVIOUS_BASE_DESTROYED", false)) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", 60000, npc, null); + } + break; + } + case "CANNON_LOOP_ATTACK": + { + if (npc.getCurrentHpPercent() > 30) + { + if (npcVars.getBoolean("IS_DESTROY_ACTIVATED", false) || (getRandom(10) < 2)) + { + final Npc cannonSkill = addSpawn(WATER_CANNON_SKILL, npc, true, 0, false, instance.getId()); + addSkillCastDesire(cannonSkill, cannonSkill, WATER_CANNON_SKILL_ATTACK, 23); + } + } + break; + } + case "SUICIDE_TIMER": + { + npc.doDie(null); + break; + } + } + } + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (npc.getId()) + { + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (!npcVars.getBoolean("CLOSED_DOORS", false)) + { + npcVars.set("CLOSED_DOORS", true); + instance.openCloseDoor(RAID_DOOR_2, false); + } + } + case WATER_CANNON: + { + if ((skill != null) && (skill.getId() == DESTROY_SKILL.getSkillId()) && !npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npcVars.set("IS_DESTROY_ACTIVATED", true); + npc.setDisplayEffect(2); + getTimers().addTimer("SUICIDE_TIMER", 60000, npc, null); + } + + if (npc.getCurrentHpPercent() < 30) + { + if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(3); + + } + } + else if (!npcVars.getBoolean("IS_DESTROY_ACTIVATED", false)) + { + npc.setDisplayEffect(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + switch (npc.getId()) + { + case VERIDAN_NORMAL: + case VERIDAN_WISE: + case VERIDAN_WEALTHY: + case VERIDAN_ARMED: + { + if (instance.getAliveNpcs(VERIDAN_NORMAL, VERIDAN_WISE, VERIDAN_WEALTHY, VERIDAN_ARMED).isEmpty()) + { + instance.finishInstance(); + } + else + { + instance.setReenterTime(); + } + break; + } + case WATER_CANNON: + { + npc.setDisplayEffect(4); + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_S1, ExShowScreenMessage.MIDDLE_CENTER, 4000, String.valueOf(npc.getParameters().getInt("base_id", -1))); + + World.getInstance().forEachVisibleObjectInRange(npc, MonsterInstance.class, 400, monster -> + { + if ((monster.getId() == STRONGHOLD_PROTECTOR) || (monster.getId() == SQUARE_INTRUDER) || (monster.getId() == SQUARE_ATTACKER)) + { + monster.doDie(null); + } + }); + + instance.getAliveNpcs(WATER_CANNON).forEach(cannon -> + { + final int cannonBaseId = cannon.getParameters().getInt("base_id", -1); + + switch (baseId) + { + case 1: + { + if (cannonBaseId == 2) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 2: + { + if (cannonBaseId == 3) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 3: + { + if (cannonBaseId == 4) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 4: + { + if ((cannonBaseId == 5) || (cannonBaseId == 6)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 5: + case 6: + { + if (cannonBaseId == 7) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + case 7: + { + if ((cannonBaseId == 8) || (cannonBaseId == 9)) + { + cannon.getVariables().set("PREVIOUS_BASE_DESTROYED", true); + cannon.setTargetable(true); + } + break; + } + } + }); + + if ((baseId == 8) || (baseId == 9)) + { + instance.getParameters().increaseInt("MAIN_TARGETS_KILLED", 0, 1); + + if (instance.getParameters().getInt("MAIN_TARGETS_KILLED", 0) == 2) + { + showOnScreenMsg(instance, NpcStringId.SUCCESSFUL_DESTRUCTION_OF_STRONGHOLD_ENTRY_ACCESSED, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.openCloseDoor(RAID_DOOR_1, true); + instance.openCloseDoor(RAID_DOOR_2, true); + + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = VERIDAN_NORMAL; + } + else if (random < 80) + { + bossId = VERIDAN_WISE; + } + else if (random < 95) + { + bossId = VERIDAN_WEALTHY; + } + else + { + bossId = VERIDAN_ARMED; + } + + for (Location loc : BOSS_SPAWNS) + { + addSpawn(bossId, loc, false, 0, false, instance.getId()); + } + } + } + } + } + } + return super.onKill(npc, killer, isSummon); + } + + @Override + public String onSpellFinished(Npc npc, PlayerInstance player, Skill skill) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance) && (npc.getId() == WATER_CANNON_SKILL) && (skill.getId() == WATER_CANNON_SKILL_ATTACK.getSkillId())) + { + npc.deleteMe(); + } + return super.onSpellFinished(npc, player, skill); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case WATER_CANNON: + { + final StatsSet npcParams = npc.getParameters(); + final int baseId = npcParams.getInt("base_id", -1); + + if (baseId != 1) + { + npc.setTargetable(false); + } + + getTimers().addTimer("HP_REGEN_TIMER", 10000, npc, null); + + if (baseId > 0) + { + getTimers().addTimer("SUPPORT_SPAWN_TIMER", (baseId * 60) * 1000, npc, null); + } + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + public void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance world = npc.getInstanceWorld(); + + if ((world != null) && creature.isPlayer() && npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.setDisplayEffect(1); + getTimers().addRepeatingTimer("CANNON_LOOP_ATTACK", 1000, npc, null); + } + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + public static void main(String[] args) + { + new CrystalCavernsEmeraldSquare(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java new file mode 100644 index 0000000000..23f045e3fd --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/CrystalCavernsSteamCorridor.java @@ -0,0 +1,408 @@ +/* + * 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 instances.CrystalCaverns; + +import org.l2jmobius.gameserver.enums.ChatType; +import org.l2jmobius.gameserver.instancemanager.ZoneManager; +import org.l2jmobius.gameserver.model.Location; +import org.l2jmobius.gameserver.model.StatsSet; +import org.l2jmobius.gameserver.model.WorldObject; +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.events.impl.creature.OnCreatureSee; +import org.l2jmobius.gameserver.model.holders.SkillHolder; +import org.l2jmobius.gameserver.model.instancezone.Instance; +import org.l2jmobius.gameserver.model.zone.ZoneType; +import org.l2jmobius.gameserver.model.zone.type.TeleportZone; +import org.l2jmobius.gameserver.network.NpcStringId; +import org.l2jmobius.gameserver.network.serverpackets.ExSendUIEvent; +import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage; + +import instances.AbstractInstance; + +/** + * Crystal Caverns - Steam Corridor instance zone. + * @author St3eT + */ +public class CrystalCavernsSteamCorridor extends AbstractInstance +{ + // NPCs + private static final int CAVERNS_ENTRACE = 33522; + private static final int KECHI_NORMAL = 25797; + private static final int KECHI_WISE = 26113; + private static final int KECHI_WEALTHY = 26112; + private static final int KECHI_ARMED = 26111; + private static final int VICIOUS_DUELER = 23014; + private static final int VICIOUS_WARRIOR = 23016; + private static final int VICIOUS_SWORDSMAN = 23015; + private static final int SPIRIT_PROTECTOR = 23013; + private static final int FIRE_REGION = 19161; + private static final int PLAYER_DETECTOR = 19075; + private static final int TRAP_1 = 19011; + private static final int TRAP_2 = 19012; + // Skills + private static final SkillHolder FIRE_SKILL_1 = new SkillHolder(14373, 1); + private static final SkillHolder FIRE_SKILL_2 = new SkillHolder(14373, 2); + private static final SkillHolder FIRE_SKILL_3 = new SkillHolder(14197, 1); + private static final SkillHolder TRAP_SKILL_1 = new SkillHolder(14180, 1); + private static final SkillHolder TRAP_SKILL_2 = new SkillHolder(14181, 1); + private static final SkillHolder TRAP_SKILL_3 = new SkillHolder(14372, 1); + // Location + private static final Location BOSS_LOC = new Location(154078, 215125, -12140); + // Misc + private static final int TEMPLATE_ID = 164; + + public CrystalCavernsSteamCorridor() + { + super(TEMPLATE_ID); + addStartNpc(CAVERNS_ENTRACE); + addTalkId(CAVERNS_ENTRACE); + addAttackId(TRAP_1, TRAP_2); + addKillId(VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, KECHI_NORMAL, KECHI_WISE, KECHI_WEALTHY, KECHI_ARMED); + addSpawnId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN, FIRE_REGION, PLAYER_DETECTOR); + addEventReceivedId(SPIRIT_PROTECTOR, VICIOUS_DUELER, VICIOUS_WARRIOR, VICIOUS_SWORDSMAN); + addInstanceCreatedId(TEMPLATE_ID); + addInstanceEnterId(TEMPLATE_ID); + addInstanceLeaveId(TEMPLATE_ID); + setCreatureSeeId(this::onCreatureSee, PLAYER_DETECTOR); + } + + @Override + public void onTimerEvent(String event, StatsSet params, Npc npc, PlayerInstance player) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcVars = npc.getVariables(); + + switch (event) + { + case "FIRE_REGION_TIMER_1": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_1, 23); + getTimers().addTimer("FIRE_REGION_TIMER_2", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_2": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_2, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 10000, npc, null); + break; + } + case "FIRE_REGION_TIMER_3": + { + addSkillCastDesire(npc, npc, FIRE_SKILL_3, 23); + getTimers().addTimer("FIRE_REGION_TIMER_3", 1000, npc, null); + break; + } + case "TRAP_REACT_TIMER": + { + final int timer = npcVars.increaseInt("TIMER_VAL", -1); + if (timer > 0) + { + npc.broadcastSay(ChatType.NPC_GENERAL, " " + timer); + } + else + { + if (npc.getId() == TRAP_1) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_1 : TRAP_SKILL_3), 23); + } + else if (npc.getId() == TRAP_2) + { + addSkillCastDesire(npc, npc, (getRandom(10) < 8 ? TRAP_SKILL_2 : TRAP_SKILL_3), 23); + } + } + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + break; + } + } + } + } + + @Override + public String onAdvEvent(String event, Npc npc, PlayerInstance player) + { + if (event.equals("enterInstance")) + { + enterInstance(player, npc, TEMPLATE_ID); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public void onInstanceCreated(Instance instance, PlayerInstance player) + { + instance.setStatus(1); + for (int i = 0; i < 6; i++) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName("24_24_fire_telezone_0" + i, TeleportZone.class); + if (zone != null) + { + zone.setEnabled(false, instance.getId()); + } + } + super.onInstanceCreated(instance, player); + } + + @Override + public void onInstanceEnter(PlayerInstance player, Instance instance) + { + final int startTime = (int) (instance.getElapsedTime() / 1000); + final int endTime = (int) (instance.getRemainingTime() / 1000); + player.sendPacket(new ExSendUIEvent(player, false, true, startTime, endTime, NpcStringId.ELAPSED_TIME)); + } + + @Override + public void onInstanceLeave(PlayerInstance player, Instance instance) + { + player.sendPacket(new ExSendUIEvent(player, true, true, 0, 0, NpcStringId.ELAPSED_TIME)); + } + + @Override + public String onSpawn(Npc npc) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case SPIRIT_PROTECTOR: + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + npc.setTargetable(false); + npc.disableCoreAI(true); + npc.setInvisible(true); + break; + } + case FIRE_REGION: + { + final int timeLimit = npcParams.getInt("Limit_Time", 0); + if (timeLimit > 0) + { + getTimers().addTimer("FIRE_REGION_TIMER_1", ((timeLimit * 30) * 100), npc, null); + } + npc.setTargetable(false); + npc.setIsInvul(true); + npc.setRandomAnimation(false); + npc.setRandomWalking(false); + npc.disableCoreAI(true); + break; + } + case PLAYER_DETECTOR: + { + npc.initSeenCreatures(); + break; + } + } + } + return super.onSpawn(npc); + } + + @Override + public String onEventReceived(String eventName, Npc sender, Npc receiver, WorldObject reference) + { + final Instance instance = receiver.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = receiver.getParameters(); + + if (eventName.equals(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)))) + { + receiver.setTargetable(true); + receiver.disableCoreAI(false); + receiver.setInvisible(false); + } + } + return super.onEventReceived(eventName, sender, receiver, reference); + } + + @Override + public String onAttack(Npc npc, PlayerInstance attacker, int damage, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + switch (npc.getId()) + { + case TRAP_1: + case TRAP_2: + { + if (npc.isScriptValue(0)) + { + getTimers().addTimer("TRAP_REACT_TIMER", 1000, npc, null); + npc.setScriptValue(1); + } + break; + } + } + } + return super.onAttack(npc, attacker, damage, isSummon); + } + + @Override + public String onKill(Npc npc, PlayerInstance killer, boolean isSummon) + { + final Instance instance = npc.getInstanceWorld(); + if (isInInstance(instance)) + { + final StatsSet npcParams = npc.getParameters(); + final int killTarget = instance.getParameters().getInt("KILL_TARGET", 5); + int currentKillCount = instance.getParameters().getInt("KILL_COUNT", 0); + + switch (npc.getId()) + { + case VICIOUS_DUELER: + case VICIOUS_WARRIOR: + case VICIOUS_SWORDSMAN: + { + if (npcParams.getInt("last_checker", 0) == 1) + { + currentKillCount = instance.getParameters().increaseInt("KILL_COUNT", 0, 1); + + if (currentKillCount >= killTarget) + { + final ZoneType zone = ZoneManager.getInstance().getZoneByName(npc.getParameters().getString("AreaTeleName"), TeleportZone.class); + if (zone != null) + { + zone.setEnabled(true, instance.getId()); + showOnScreenMsg(instance, NpcStringId.THE_PORTAL_TO_THE_NEXT_ROOM_IS_NOW_OPEN, ExShowScreenMessage.MIDDLE_CENTER, 4000); + instance.spawnGroup("innadril23_mb2422_pt" + instance.getStatus() + "m1"); + instance.getParameters().set("KILL_COUNT", 0); + + switch (instance.getStatus()) + { + case 1: + { + instance.getParameters().set("KILL_TARGET", 12); + instance.setStatus(2); + break; + } + case 2: + { + instance.getParameters().set("KILL_TARGET", 3); + instance.setStatus(3); + break; + } + case 3: + { + instance.getParameters().set("KILL_TARGET", 18); + instance.setStatus(4); + break; + } + case 4: + { + instance.getParameters().set("KILL_TARGET", 5); + instance.setStatus(5); + break; + } + case 5: + { + instance.getParameters().set("KILL_TARGET", 20); + instance.setStatus(6); + break; + } + case 6: + { + final int random = getRandom(100); + int bossId = -1; + + if (random < 55) + { + bossId = KECHI_NORMAL; + } + else if (random < 80) + { + bossId = KECHI_WISE; + } + else if (random < 95) + { + bossId = KECHI_WEALTHY; + } + else + { + bossId = KECHI_ARMED; + } + + addSpawn(bossId, BOSS_LOC, false, 0, false, instance.getId()); + break; + } + } + } + else + { + LOGGER.warning("Cannot find teleport zone for Crystal Cavern: Steam Corridor instance!!!"); + } + } + } + break; + } + case KECHI_NORMAL: + case KECHI_WISE: + case KECHI_WEALTHY: + case KECHI_ARMED: + { + instance.finishInstance(); + break; + } + } + } + return super.onKill(npc, killer, isSummon); + } + + private void onCreatureSee(OnCreatureSee event) + { + final Creature creature = event.getSeen(); + final Npc npc = (Npc) event.getSeer(); + final Instance instance = npc.getInstanceWorld(); + + if (isInInstance(instance) && creature.isPlayer()) + { + final StatsSet npcParams = npc.getParameters(); + + switch (npc.getId()) + { + case PLAYER_DETECTOR: + { + if (npc.isScriptValue(0)) + { + npc.setScriptValue(1); + npc.broadcastEvent(String.valueOf(24220005 + npcParams.getInt("Terri_ID", 0)), 2000, null); + + for (int i = 0; i < getRandom(5); i++) + { + final Npc trap = addSpawn(((npcParams.getInt("MobType", 0) == 0) ? TRAP_1 : TRAP_2), npc, true, 0, false, instance.getId()); + trap.getVariables().set("TIMER_VAL", 4); + } + npc.deleteMe(); + } + break; + } + } + } + } + + public static void main(String[] args) + { + new CrystalCavernsSteamCorridor(); + } +} \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html new file mode 100644 index 0000000000..efc886f117 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/condNoParty.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+You must be in a party to enter. + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html new file mode 100644 index 0000000000..dfa8583852 --- /dev/null +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/scripts/instances/CrystalCaverns/condNoPartyLeader.html @@ -0,0 +1,3 @@ +Crystal Caverns Admission Portal:
+The leader of the party should try to enter. + \ No newline at end of file diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/stats/npcs/19000-19099.xml b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/stats/npcs/19000-19099.xml index d1a15f1afa..47a6497a67 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/stats/npcs/19000-19099.xml +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/stats/npcs/19000-19099.xml @@ -366,7 +366,7 @@ - + @@ -403,7 +403,7 @@ - + diff --git a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/zones/teleportzones.xml b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/zones/teleportzones.xml index 58d7790d91..417a27bcf4 100644 --- a/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/zones/teleportzones.xml +++ b/L2J_Mobius_7.0_PreludeOfWar/dist/game/data/zones/teleportzones.xml @@ -154,6 +154,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +