Jump to content

Cherish

Members
  • Posts

    52
  • Credits

  • Joined

  • Last visited

  • Feedback

    0%

Everything posted by Cherish

  1. I share this piece code here as it will be likely end up declined and then pushed from some-one else. The code resembles retail-like implementation of tears and cystal golems AI. Improves over-all experience by resolving notable number of issues and formatted for readability. NOTE: Kechi's henchmen requires AI implementation, poison traps at Dernel and exploding traps at Steam Corridor must be implemented. This code is improved version and will try and keep it up to date, original release can be found on the following link. https://bitbucket.org/l2jserver/l2j-server-datapack/pull-requests/90 Simple adaption should do for most L2J Projects. /* * Copyright © 2004-2022 L2J DataPack * * This file is part of L2J DataPack. * * L2J DataPack 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. * * L2J DataPack 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 <http://www.gnu.org/licenses/>. */ package com.l2jserver.datapack.instances.CrystalCaverns; import com.l2jserver.datapack.instances.AbstractInstance; import com.l2jserver.datapack.quests.Q00131_BirdInACage.Q00131_BirdInACage; import com.l2jserver.gameserver.GeoData; import com.l2jserver.gameserver.ai.CtrlIntention; import com.l2jserver.gameserver.enums.TrapAction; import com.l2jserver.gameserver.instancemanager.InstanceManager; import com.l2jserver.gameserver.model.L2Object; import com.l2jserver.gameserver.model.L2Party; import com.l2jserver.gameserver.model.L2World; import com.l2jserver.gameserver.model.Location; import com.l2jserver.gameserver.model.PcCondOverride; import com.l2jserver.gameserver.model.actor.L2Attackable; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.actor.L2Npc; import com.l2jserver.gameserver.model.actor.L2Summon; import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.actor.instance.L2TrapInstance; import com.l2jserver.gameserver.model.entity.Instance; import com.l2jserver.gameserver.model.holders.SkillHolder; import com.l2jserver.gameserver.model.instancezone.InstanceWorld; import com.l2jserver.gameserver.model.items.instance.L2ItemInstance; import com.l2jserver.gameserver.model.quest.QuestState; import com.l2jserver.gameserver.model.skills.Skill; import com.l2jserver.gameserver.model.zone.L2ZoneType; import com.l2jserver.gameserver.network.NpcStringId; import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.clientpackets.Say2; import com.l2jserver.gameserver.network.serverpackets.CreatureSay; import com.l2jserver.gameserver.network.serverpackets.FlyToLocation; import com.l2jserver.gameserver.network.serverpackets.FlyToLocation.FlyType; import com.l2jserver.gameserver.network.serverpackets.MagicSkillUse; import com.l2jserver.gameserver.network.serverpackets.SpecialCamera; import com.l2jserver.gameserver.network.serverpackets.SystemMessage; import com.l2jserver.gameserver.network.serverpackets.ValidateLocation; import com.l2jserver.gameserver.util.Util; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import static com.l2jserver.gameserver.config.Configuration.rates; /** * Crystal Caverns instance zone.<br> * TODO: 1. Kechi's Henchmans spawn AI is missing.<br> * 2. Poison traps at Dernels and Explosion traps at Steam Corridor require implementation.<br> * 3. Baylor Raid is missing a lot of things This script takes the best elements of different versions and combines them into one script to get the most optimal and retail-like experience.<br> * Original sources: theone, L2JEmu, L2JOfficial, L2JFree Contributing authors: TGS, Lantoc, Janiii, Gigiikun, RosT, Cherish, Lomka.<br> * Please maintain consistency between the Crystal Caverns scripts.<br> */ public final class CrystalCaverns extends AbstractInstance { protected static class CrystalGolem { protected L2ItemInstance foodItem = null; protected Location newLoc = null; protected Location oldLoc = null; protected boolean golemHasBeenFed = false; protected boolean isAtFinalDestination = false; } private class CCWorld extends InstanceWorld { public Map<L2Npc, CrystalGolem> crystalGolems = new HashMap<>(); public boolean golemIsAtFinalDestination1 = false; public boolean golemIsAtFinalDestination2 = false; // tears and world related variables public Map<L2Npc, Boolean> npcList1 = new HashMap<>(); public List<L2Npc> copies = new ArrayList<>(); private final String damageTracker = "damageTracker"; public boolean isUsedInvulSkill = false; public int tearsStatus = 0; public long dragonScaleStart = 0; public int dragonScaleNeed = 0; public int cleanedRooms = 0; public long endTime = 0; public boolean[] oracleTriggered = { false, false, false }; public int kechisHenchmanSpawn = 0; public int[] roomsStatus = { 0, 0, 0, 0 }; // 0: not spawned, 1: spawned, 2: cleared public Map<L2DoorInstance, L2PcInstance> openedDoors = new ConcurrentHashMap<>(); public Map<Integer, Map<L2Npc, Boolean>> npcList2 = new HashMap<>(); public Map<L2Npc, L2Npc> oracles = new HashMap<>(); public List<L2Npc> keyKeepers = new ArrayList<>(); public List<L2Npc> guards = new ArrayList<>(); public List<L2Npc> oracle = new ArrayList<>(); // baylor variables protected final List<L2PcInstance> raiders = new ArrayList<>(); protected int raidStatus = 0; protected long dragonClawStart = 0; protected int dragonClawNeed = 0; protected final List<L2Npc> animationMobs = new ArrayList<>(); protected L2Npc camera = null; protected L2Npc baylor = null; protected L2Npc alarm = null; public CCWorld(Long time) { endTime = time; } } // Items private static final int WHITE_SEED_OF_EVIL_SHARD = 9597; private static final int BLACK_SEED_OF_EVIL_SHARD = 9598; private static final int CONTAMINATED_CRYSTAL = 9690; private static final int RED_CORAL = 9692; private static final int CRYSTAL_FRAGMENT = 9693; private static final int SECRET_KEY = 9694; private static final int BLUE_CRYSTAL = 9695; private static final int RED_CRYSTAL = 9696; private static final int CLEAR_CRYSTAL = 9697; private static final int BLUE_CORAL_KEY = 9698; private static final int RED_CORAL_KEY = 9699; // NPCs private static final int PARME = 32271; private static final int TREASURE_CHEST_1 = 29116; private static final int TREASURE_CHEST_2 = 29117; private static final int ORACLE_GUIDE_1 = 32281; private static final int ORACLE_GUIDE_2 = 32278; private static final int ORACLE_GUIDE_3 = 32280; private static final int ORACLE_GUIDE_4 = 32279; private static final int ORACLE_GUIDE_5 = 32275; private static final int ORACLE_GUIDE_6 = 32277; private static final int ORACLE_GUIDE_7 = 32274; private static final int ORACLE_GUIDE_8 = 32276; private static final int CRYSTALLINE_GOLEM = 32328; private static final int GATEKEEPER_LOHAN = 22275; private static final int GATEKEEPER_PROVO = 22277; private static final int TOURMALINE = 22292; private static final int TEROD = 22301; private static final int DOLPH = 22299; private static final int WEYLIN = 22298; private static final int GUARDIAN_OF_THE_SQUARE = 22303; private static final int GUARDIAN_OF_THE_EMERALD = 22304; private static final int TEARS = 25534; private static final int TEARS_COPY = 25535; private static final int KECHI = 25532; private static final int KECHIS_HENCHMAN = 25533; private static final int BAYLOR = 29099; private static final int CRYSTAL_PRISON_GUARD = 29104; private static final int DARNEL = 25531; private static final int ALARM = 18474; private static final int[] DOOR_OPENING_TRAP = { 18378, 143680, 142608, -11845, 0 }; private static final int[] CGMOBS = { 22311, 22312, 22313, 22314, 22315, 22316, 22317 }; // Kechi Hencmans spawn times private static final int[] SPAWN = { 60000, 120000, 90000, 60000, 50000, 40000 }; private static final int[] MOBLIST = { 22279, 22280, 22281, 22282, 22283, 22285, 22286, 22287, 22288, 22289, 22293, 22294, 22295, 22296, 22297, 22305, 22306, 22307, 22416, 22418, 22419, 22420 }; // Locations private static final Location START_LOC = new Location(143348, 148707, -11972); private static final Location golemFinalDestination1 = new Location(142999, 151671, -11805); private static final Location golemFinalDestination2 = new Location(139494, 151668, -11805); private static final Location tearsSpawnLocation = new Location(144298, 154420, -11854, 32767); // Skills private static final SkillHolder BERSERK = new SkillHolder(5224); private static final SkillHolder INVINCIBLE = new SkillHolder(5225); private static final SkillHolder STRONG_PUNCH = new SkillHolder(5229); private static final SkillHolder EVENT_TIMER_1 = new SkillHolder(5239); private static final SkillHolder EVENT_TIMER_2 = new SkillHolder(5239, 2); private static final SkillHolder EVENT_TIMER_3 = new SkillHolder(5239, 3); private static final SkillHolder EVENT_TIMER_4 = new SkillHolder(5239, 4); private static final SkillHolder PHYSICAL_UP = new SkillHolder(5244); private static final SkillHolder MAGICAL_UP = new SkillHolder(5245); private static final SkillHolder PRESENTATION = new SkillHolder(5441); // Misc private static final int TEMPLATE_ID = 10; private static final int MIN_LEVEL = 78; private static final int DOOR1 = 24220021; private static final int DOOR2 = 24220024; private static final int DOOR3 = 24220023; private static final int DOOR4 = 24220061; private static final int DOOR5 = 24220025; private static final int DOOR6 = 24220022; private static final int DOOR7 = 24220026; private static final int DOOR8 = 24220005; private static final int DOOR9 = 24220006; private static final int DOOR10 = 24220000; private static final int DOOR11 = 24220002; private static final int DOOR12 = 24220003; private static final int DOOR13 = 24220004; private static final int DOOR14 = 24220004; private static final int[] ZONES = { 20105, 20106, 20107 }; // @formatter:off private final static int[][] ALARMSPAWN = { {153572, 141277, -12738}, {153572, 142852, -12738}, {154358, 142075, -12738}, {152788, 142075, -12738} }; // Oracle order private static final int[][] ordreOracle1 = { {32274, 147090, 152505, -12169, 31613}, {32275, 147090, 152575, -12169, 31613}, {32274, 147090, 152645, -12169, 31613}, {32274, 147090, 152715, -12169, 31613} }; private static final int[][] ordreOracle2 = { {32274, 149783, 152505, -12169, 31613}, {32274, 149783, 152645, -12169, 31613}, {32276, 149783, 152715, -12169, 31613} }; private static final int[][] ordreOracle3 = { {32274, 152461, 152505, -12169, 31613}, {32277, 152461, 152645, -12169, 31613}, }; private static int[][] HALL_SPAWNS = { {141842, 152556, -11814, 50449}, {141503, 153395, -11814, 40738}, {141070, 153201, -11814, 39292}, {141371, 152986, -11814, 35575}, {141602, 154188, -11814, 24575}, {141382, 154719, -11814, 37640}, {141376, 154359, -11814, 12054}, {140895, 154383, -11814, 37508}, {140972, 154740, -11814, 52690}, {141045, 154504, -11814, 50674}, {140757, 152740, -11814, 39463}, {140406, 152376, -11814, 16599}, {140268, 152007, -11817, 45316}, {139996, 151485, -11814, 47403}, {140378, 151190, -11814, 58116}, {140521, 150711, -11815, 55997}, {140816, 150215, -11814, 53682}, {141528, 149909, -11814, 22020}, {141644, 150360, -11817, 13283}, {142048, 150695, -11815, 5929}, {141852, 151065, -11817, 27071}, {142408, 151211, -11815, 2402}, {142481, 151762, -11815, 12876}, {141929, 152193, -11815, 27511}, {142083, 151791, -11814, 47176}, {141435, 150402, -11814, 41798}, {140390, 151199, -11814, 50069}, {140557, 151849, -11814, 45293}, {140964, 153445, -11814, 56672}, {142851, 154109, -11814, 24920}, {142379, 154725, -11814, 30342}, {142816, 154712, -11814, 33193}, {142276, 154223, -11814, 33922}, {142459, 154490, -11814, 33184}, {142819, 154372, -11814, 21318}, {141157, 154541, -11814, 27090}, {141095, 150281, -11814, 55186} }; // first spawns private static int[][] FIRST_SPAWNS = { {22276, 148109, 149601, -12132, 34490}, {22276, 148017, 149529, -12132, 33689}, {22278, 148065, 151202, -12132, 35323}, {22278, 147966, 151117, -12132, 33234}, {22279, 144063, 150238, -12132, 29654}, {22279, 144300, 149118, -12135, 5520}, {22279, 144397, 149337, -12132, 644}, {22279, 144426, 150639, -12132, 50655}, {22282, 145841, 151097, -12132, 31810}, {22282, 144387, 149958, -12132, 61173}, {22282, 145821, 149498, -12132, 31490}, {22282, 146619, 149694, -12132, 33374}, {22282, 146669, 149244, -12132, 31360}, {22284, 144147, 151375, -12132, 58395}, {22284, 144485, 151067, -12132, 64786}, {22284, 144356, 149571, -12132, 63516}, {22285, 144151, 150962, -12132, 664}, {22285, 146657, 151365, -12132, 33154}, {22285, 146623, 150857, -12132, 28034}, {22285, 147046, 151089, -12132, 32941}, {22285, 145704, 151255, -12132, 32523}, {22285, 145359, 151101, -12132, 32767}, {22285, 147785, 150817, -12132, 27423}, {22285, 147727, 151375, -12132, 37117}, {22285, 145428, 149494, -12132, 890}, {22285, 145601, 149682, -12132, 32442}, {22285, 147003, 149476, -12132, 31554}, {22285, 147738, 149210, -12132, 20971}, {22285, 147769, 149757, -12132, 34980} }; // Emerald Square private static int[][] EMERALD_SPAWNS = { {22280, 144437, 143395, -11969, 34248}, {22281, 149241, 143735, -12230, 24575}, {22281, 147917, 146861, -12289, 60306}, {22281, 144406, 147782, -12133, 14349}, {22281, 144960, 146881, -12039, 23881}, {22281, 144985, 147679, -12135, 27594}, {22283, 147784, 143540, -12222, 2058}, {22283, 149091, 143491, -12230, 24836}, {22287, 144479, 147569, -12133, 20723}, {22287, 145158, 146986, -12058, 21970}, {22287, 145142, 147175, -12092, 24420}, {22287, 145110, 147133, -12088, 22465}, {22287, 144664, 146604, -12028, 14861}, {22287, 144596, 146600, -12028, 14461}, {22288, 143925, 146773, -12037, 10813}, {22288, 144415, 147070, -12069, 8568}, {22288, 143794, 145584, -12027, 14849}, {22288, 143429, 146166, -12030, 4078}, {22288, 144477, 147009, -12056, 8752}, {22289, 142577, 145319, -12029, 5403}, {22289, 143831, 146902, -12051, 9717}, {22289, 143714, 146705, -12028, 10044}, {22289, 143937, 147134, -12078, 7517}, {22293, 143356, 145287, -12027, 8126}, {22293, 143462, 144352, -12008, 25905}, {22293, 143745, 142529, -11882, 17102}, {22293, 144574, 144032, -12005, 34668}, {22295, 143992, 142419, -11884, 19697}, {22295, 144671, 143966, -12004, 32088}, {22295, 144440, 143269, -11957, 34169}, {22295, 142642, 146362, -12028, 281}, {22295, 143865, 142707, -11881, 21326}, {22295, 143573, 142530, -11879, 16141}, {22295, 143148, 146039, -12031, 65014}, {22295, 143001, 144853, -12014, 0}, {22296, 147505, 146580, -12260, 59041}, {22296, 149366, 146932, -12358, 39407}, {22296, 149284, 147029, -12352, 41120}, {22296, 149439, 143940, -12230, 23189}, {22296, 147698, 143995, -12220, 27028}, {22296, 141885, 144969, -12007, 2526}, {22296, 147843, 143763, -12220, 28386}, {22296, 144753, 143650, -11982, 35429}, {22296, 147613, 146760, -12271, 56296} }; private static int[][] ROOM1_SPAWNS = { {22288, 143114, 140027, -11888, 15025}, {22288, 142173, 140973, -11888, 55698}, {22289, 143210, 140577, -11888, 17164}, {22289, 142638, 140107, -11888, 6571}, {22297, 142547, 140938, -11888, 48556}, {22298, 142690, 140479, -11887, 7663} }; private static int[][] ROOM2_SPAWNS = { {22303, 146276, 141483, -11880, 34643}, {22287, 145707, 142161, -11880, 28799}, {22288, 146857, 142129, -11880, 33647}, {22288, 146869, 142000, -11880, 31215}, {22289, 146897, 140880, -11880, 19210} }; private static int[][] ROOM3_SPAWNS = { {22302, 145123, 143713, -12808, 65323}, {22294, 145188, 143331, -12808, 496}, {22294, 145181, 144104, -12808, 64415}, {22293, 144994, 143431, -12808, 65431}, {22293, 144976, 143915, -12808, 61461} }; private static int[][] ROOM4_SPAWNS = { {22304, 150563, 142240, -12108, 16454}, {22294, 150769, 142495, -12108, 16870}, {22281, 150783, 141995, -12108, 20033}, {22283, 150273, 141983, -12108, 16043}, {22294, 150276, 142492, -12108, 13540} }; // Steam Corridor private static int[][] STEAM1_SPAWNS = { {22305, 145260, 152387, -12165, 32767}, {22305, 144967, 152390, -12165, 30464}, {22305, 145610, 152586, -12165, 17107}, {22305, 145620, 152397, -12165, 8191}, {22418, 146081, 152847, -12165, 31396}, {22418, 146795, 152641, -12165, 33850}, }; private static int[][] STEAM2_SPAWNS = { {22306, 147740, 152767, -12165, 65043}, {22306, 148215, 152828, -12165, 970}, {22306, 147743, 152846, -12165, 64147}, {22418, 148207, 152725, -12165, 61801}, {22419, 149058, 152828, -12165, 64564} }; private static int[][] STEAM3_SPAWNS = { {22307, 150735, 152316, -12145, 31930}, {22307, 150725, 152467, -12165, 33635}, {22307, 151058, 152316, -12146, 65342}, {22307, 151057, 152461, -12165, 2171}, }; private static int[][] STEAM4_SPAWNS = { {22416, 151636, 150280, -12142, 36869}, {22416, 149893, 150232, -12165, 64258}, {22416, 149864, 150110, -12165, 65054}, {22416, 151926, 150218, -12165, 31613}, {22420, 149986, 150051, -12165, 105}, {22420, 151970, 149997, -12165, 32170}, {22420, 150744, 150006, -12165, 63}, }; // @formatter:on private static final int DRAGONSCALETIME = 3000; private static final int DRAGONCLAWTIME = 3000; public CrystalCaverns() { super(CrystalCaverns.class.getSimpleName()); addStartNpc(ORACLE_GUIDE_1, ORACLE_GUIDE_3, ORACLE_GUIDE_4); addTalkId(ORACLE_GUIDE_1, ORACLE_GUIDE_3, ORACLE_GUIDE_4, ORACLE_GUIDE_5, ORACLE_GUIDE_6, ORACLE_GUIDE_8); addFirstTalkId(ORACLE_GUIDE_1, ORACLE_GUIDE_2, ORACLE_GUIDE_3, ORACLE_GUIDE_4, ORACLE_GUIDE_5, ORACLE_GUIDE_6, ORACLE_GUIDE_7, ORACLE_GUIDE_8, CRYSTALLINE_GOLEM); addKillId(TEARS, GATEKEEPER_LOHAN, GATEKEEPER_PROVO, TEROD, WEYLIN, DOLPH, DARNEL, KECHI, GUARDIAN_OF_THE_SQUARE, GUARDIAN_OF_THE_EMERALD, TOURMALINE, BAYLOR, ALARM); addSkillSeeId(BAYLOR, TEARS, ORACLE_GUIDE_5, ORACLE_GUIDE_6, ORACLE_GUIDE_8); addTrapActionId(DOOR_OPENING_TRAP[0]); addSpellFinishedId(BAYLOR); addAttackId(TEARS, TEARS_COPY); addKillId(MOBLIST); addKillId(CGMOBS); addEnterZoneId(ZONES); addExitZoneId(ZONES); } @Override protected boolean checkConditions(L2PcInstance player) { if (player.canOverrideCond(PcCondOverride.INSTANCE_CONDITIONS)) { return true; } final L2Party party = player.getParty(); if (party == null) { player.sendPacket(SystemMessageId.NOT_IN_PARTY_CANT_ENTER); return false; } if (party.getLeader() != player) { player.sendPacket(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER); return false; } for (L2PcInstance partyMember : party.getMembers()) { if (partyMember.getLevel() < MIN_LEVEL) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_S_LEVEL_REQUIREMENT_IS_NOT_SUFFICIENT_AND_CANNOT_BE_ENTERED); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } L2ItemInstance item = partyMember.getInventory().getItemByItemId(CONTAMINATED_CRYSTAL); if (item == null) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_ITEM_REQUIREMENT_NOT_SUFFICIENT); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } if (!Util.checkIfInRange(1000, player, partyMember, true)) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_A_LOCATION_WHICH_CANNOT_BE_ENTERED_THEREFORE_IT_CANNOT_BE_PROCESSED); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } if (System.currentTimeMillis() < InstanceManager.getInstance().getInstanceTime(partyMember.getObjectId(), TEMPLATE_ID)) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_MAY_NOT_RE_ENTER_YET); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } } return true; } private boolean checkOracleConditions(L2PcInstance player) { if (player.canOverrideCond(PcCondOverride.INSTANCE_CONDITIONS)) { return true; } L2Party party = player.getParty(); if (party == null) { player.sendPacket(SystemMessageId.NOT_IN_PARTY_CANT_ENTER); return false; } if (party.getLeader() != player) { player.sendPacket(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER); return false; } for (L2PcInstance partyMember : party.getMembers()) { L2ItemInstance item = partyMember.getInventory().getItemByItemId(RED_CORAL); if (item == null) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_ITEM_REQUIREMENT_NOT_SUFFICIENT); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } if (!Util.checkIfInRange(1000, player, partyMember, true)) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_A_LOCATION_WHICH_CANNOT_BE_ENTERED_THEREFORE_IT_CANNOT_BE_PROCESSED); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } } return true; } private boolean checkBaylorConditions(L2PcInstance player) { if (player.canOverrideCond(PcCondOverride.INSTANCE_CONDITIONS)) { return true; } L2Party party = player.getParty(); if (party == null) { player.sendPacket(SystemMessageId.NOT_IN_PARTY_CANT_ENTER); return false; } if (party.getLeader() != player) { player.sendPacket(SystemMessageId.ONLY_PARTY_LEADER_CAN_ENTER); return false; } for (L2PcInstance partyMember : party.getMembers()) { L2ItemInstance item1 = partyMember.getInventory().getItemByItemId(BLUE_CRYSTAL); L2ItemInstance item2 = partyMember.getInventory().getItemByItemId(RED_CRYSTAL); L2ItemInstance item3 = partyMember.getInventory().getItemByItemId(CLEAR_CRYSTAL); if ((item1 == null) || (item2 == null) || (item3 == null)) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_ITEM_REQUIREMENT_NOT_SUFFICIENT); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } if (!Util.checkIfInRange(1000, player, partyMember, true)) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_IN_A_LOCATION_WHICH_CANNOT_BE_ENTERED_THEREFORE_IT_CANNOT_BE_PROCESSED); sm.addPcName(partyMember); party.broadcastPacket(sm); return false; } } return true; } // this should be handled from skill effect private void Throw(L2Character effector, L2Character effected) { // Get current position of the L2Character final int curX = effected.getX(); final int curY = effected.getY(); final int curZ = effected.getZ(); // Calculate distance between effector and effected current position double dx = effector.getX() - curX; double dy = effector.getY() - curY; double dz = effector.getZ() - curZ; double distance = Math.sqrt((dx * dx) + (dy * dy)); int offset = Math.min((int) distance + 300, 1400); double cos; double sin; // approximation for moving further when z coordinates are different // TODO: handle Z axis movement better offset += Math.abs(dz); if (offset < 5) { offset = 5; } if (distance < 1) { return; } // Calculate movement angles needed sin = dy / distance; cos = dx / distance; // Calculate the new destination with offset included int _x = effector.getX() - (int) (offset * cos); int _y = effector.getY() - (int) (offset * sin); int _z = effected.getZ(); Location destination = GeoData.getInstance().moveCheck(effected.getX(), effected.getY(), effected.getZ(), _x, _y, _z, effected.getInstanceId()); effected.broadcastPacket(new FlyToLocation(effected, destination, FlyType.THROW_UP)); // maybe is need force set X,Y,Z effected.setXYZ(destination); effected.broadcastPacket(new ValidateLocation(effected)); } @Override public void onEnterInstance(L2PcInstance player, InstanceWorld world, boolean firstEntrance) { if (firstEntrance) { Optional.ofNullable(player.getParty()).map(L2Party::getMembers).orElseGet(() -> List.of(player)) .forEach(member -> { teleportPlayer(member, START_LOC, world.getInstanceId()); world.addAllowed(member.getObjectId()); }); runOracle((CCWorld) world); } else { teleportPlayer(player, START_LOC, world.getInstanceId()); } } protected void runOracle(CCWorld world) { world.setStatus(0); world.oracle.add(addSpawn(ORACLE_GUIDE_1, 143172, 148894, -11975, 0, false, 0, false, world.getInstanceId())); } protected void runEmerald(CCWorld world) { world.setStatus(1); runFirst(world); openDoor(DOOR1, world.getInstanceId()); } protected void runCoral(CCWorld world) { world.setStatus(1); runHall(world); openDoor(DOOR2, world.getInstanceId()); openDoor(DOOR5, world.getInstanceId()); } protected void runHall(CCWorld world) { world.setStatus(2); for (int[] spawn : HALL_SPAWNS) { L2Npc mob = addSpawn(CGMOBS[getRandom(CGMOBS.length)], spawn[0], spawn[1], spawn[2], spawn[3], false, 0, false, world.getInstanceId()); world.npcList1.put(mob, false); } } protected void runFirst(CCWorld world) { world.setStatus(2); world.keyKeepers.add(addSpawn(GATEKEEPER_LOHAN, 148206, 149486, -12140, 32308, false, 0, false, world.getInstanceId())); world.keyKeepers.add(addSpawn(GATEKEEPER_PROVO, 148203, 151093, -12140, 31100, false, 0, false, world.getInstanceId())); for (int[] spawn : FIRST_SPAWNS) { addSpawn(spawn[0], spawn[1], spawn[2], spawn[3], spawn[4], false, 0, false, world.getInstanceId()); } } protected void runEmeraldSquare(CCWorld world) { world.setStatus(3); Map<L2Npc, Boolean> spawnList = new HashMap<>(); for (int[] spawn : EMERALD_SPAWNS) { L2Npc mob = addSpawn(spawn[0], spawn[1], spawn[2], spawn[3], spawn[4], false, 0, false, world.getInstanceId()); spawnList.put(mob, false); } world.npcList2.put(0, spawnList); } protected void runEmeraldRooms(CCWorld world, int[][] spawnList, int room) { Map<L2Npc, Boolean> spawned = new HashMap<>(); for (int[] spawn : spawnList) { L2Npc mob = addSpawn(spawn[0], spawn[1], spawn[2], spawn[3], spawn[4], false, 0, false, world.getInstanceId()); spawned.put(mob, false); } if (room == 1) { addSpawn(32359, 142110, 139896, -11888, 8033, false, 0, false, world.getInstanceId()); } world.npcList2.put(room, spawned); world.roomsStatus[room - 1] = 1; } protected void runDarnel(CCWorld world) { world.setStatus(9); addSpawn(DARNEL, 152759, 145949, -12588, 21592, false, 0, false, world.getInstanceId()); // TODO: missing traps openDoor(DOOR8, world.getInstanceId()); openDoor(DOOR9, world.getInstanceId()); } protected void runSteamRooms(CCWorld world, int[][] spawnList, int status) { world.setStatus(status); Map<L2Npc, Boolean> spawned = new HashMap<>(); for (int[] spawn : spawnList) { L2Npc mob = addSpawn(spawn[0], spawn[1], spawn[2], spawn[3], spawn[4], false, 0, false, world.getInstanceId()); spawned.put(mob, false); } world.npcList2.put(0, spawned); } protected void runSteamOracles(CCWorld world, int[][] oracleOrder) { world.oracles.clear(); for (int[] oracle : oracleOrder) { world.oracles.put(addSpawn(oracle[0], oracle[1], oracle[2], oracle[3], oracle[4], false, 0, false, world.getInstanceId()), null); } } protected boolean checkKillProgress(int room, L2Npc mob, CCWorld world) { if (world.npcList2.get(room).containsKey(mob)) { world.npcList2.get(room).put(mob, true); } for (boolean isDead : world.npcList2.get(room).values()) { if (!isDead) { return false; } } return true; } @Override public String onFirstTalk(L2Npc npc, L2PcInstance player) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { CrystalGolem cryGolem = world.crystalGolems.get(npc); if (npc.getId() == ORACLE_GUIDE_1) { if ((world.getStatus() == 0) && world.oracle.contains(npc)) { return "32281.htm";// TODO: Missing HTML. } npc.showChatWindow(player); return null; } else if (npc.getId() == ORACLE_GUIDE_3) { return "32280.htm"; // TODO: Missing HTML. } else if ((npc.getId() >= ORACLE_GUIDE_5) && (npc.getId() <= ORACLE_GUIDE_6)) { if (!world.oracleTriggered[npc.getId() - ORACLE_GUIDE_5]) { return "no.htm"; // TODO: Missing HTML. } npc.showChatWindow(player); return null; } else if (npc.getId() == ORACLE_GUIDE_7) { return "no.htm"; // TODO: Missing HTML. } else if (npc.getId() == ORACLE_GUIDE_4) { final QuestState st = player.getQuestState(Q00131_BirdInACage.class.getSimpleName()); return (st != null) && !st.isCompleted() ? "32279-01.htm" : "32279.htm"; } else if (npc.getId() == CRYSTALLINE_GOLEM && !cryGolem.isAtFinalDestination) { //to be implemented dialog cooldown. broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.AH_IM_HUNGRY); } } else if (npc.getId() == ORACLE_GUIDE_1) { npc.showChatWindow(player); return null; } return ""; } @Override public String onSkillSee(L2Npc npc, L2PcInstance caster, Skill skill, List<L2Object> targets, boolean isSummon) { boolean doReturn = true; for (L2Object obj : targets) { if (obj == npc) { doReturn = false; } } if (doReturn) { return super.onSkillSee(npc, caster, skill, targets, isSummon); } switch (skill.getId()) { case 1011: case 1015: case 1217: case 1218: case 1401: case 2360: case 2369: case 5146: doReturn = false; break; default: doReturn = true; } if (doReturn) { return super.onSkillSee(npc, caster, skill, targets, isSummon); } if ((npc.getId() >= ORACLE_GUIDE_5) && (npc.getId() <= ORACLE_GUIDE_6) && (skill.getId() != 2360) && (skill.getId() != 2369)) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if ((tmpworld instanceof CCWorld) && (getRandom(100) < 15)) { for (L2Npc oracle : ((CCWorld) tmpworld).oracles.keySet()) { if (oracle != npc) { oracle.decayMe(); } } ((CCWorld) tmpworld).oracleTriggered[npc.getId() - ORACLE_GUIDE_5] = true; } } else if (npc.isInvul() && (npc.getId() == BAYLOR) && (skill.getId() == 2360) && (caster != null)) { if (caster.getParty() == null) { return super.onSkillSee(npc, caster, skill, targets, isSummon); } InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { if (((world.dragonClawStart + DRAGONCLAWTIME) <= System.currentTimeMillis()) || (world.dragonClawNeed <= 0)) { world.dragonClawStart = System.currentTimeMillis(); world.dragonClawNeed = caster.getParty().getMemberCount() - 1; } else { world.dragonClawNeed--; } if (world.dragonClawNeed == 0) { npc.stopSkillEffects(false, 5225); npc.broadcastPacket(new MagicSkillUse(npc, npc, 5480, 1, 4000, 0)); if (world.raidStatus == 3) { world.raidStatus++; } } } } else if (npc.isInvul() && (npc.getId() == TEARS) && (skill.getId() == 2369) && (caster != null)) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { if (caster.getParty() == null) { return super.onSkillSee(npc, caster, skill, targets, isSummon); } else if (((world.dragonScaleStart + DRAGONSCALETIME) <= System.currentTimeMillis()) || (world.dragonScaleNeed <= 0)) { world.dragonScaleStart = System.currentTimeMillis(); world.dragonScaleNeed = caster.getParty().getMemberCount() - 1; } else { world.dragonScaleNeed--; } if ((world.dragonScaleNeed == 0) && (getRandom(100) < 80)) { npc.setIsInvul(false); broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.NOYOU_KNEW_MY_WEAKNESS); } } } return super.onSkillSee(npc, caster, skill, targets, isSummon); } private static final Location[] TEARS_NEW_LOCATION = { new Location(144650, 154313, -11848), new Location(144522, 154714, -11848), new Location(143968, 154328, -11848), new Location(144654, 154536, -11848), new Location(144519, 154138, -11848), new Location(144320, 154789, -11848), new Location(144301, 154070, -11848), new Location(144089, 154142, -11848), new Location(143971, 154550, -11848), new Location(144116, 154715, -11848), }; @Override public String onAttack(L2Npc npc, L2PcInstance player, int damage, boolean isSummon, Skill skill) { if (npc.getId() == TEARS) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { npc.getVariables().set(world.damageTracker, npc.getVariables().getInt(world.damageTracker) + damage); if (npc.getVariables().getInt(world.damageTracker) > 100000) { cancelQuestTimers("ApplyAggressionCopies"); for (L2Npc copy : world.copies) { if (copy != null) { copy.deleteMe(); } } } int maxHp = npc.getMaxHp(); double nowHp = npc.getStatus().getCurrentHp(); if (!world.isUsedInvulSkill) { if ((nowHp <= (maxHp * 0.8)) && (world.tearsStatus == 0)) { world.tearsStatus = 1; startQuestTimer("SpawnTearsCopies", 2000, npc, player); npc.doCast(PRESENTATION); } else if ((nowHp <= (maxHp * 0.6)) && (world.tearsStatus == 1)) { world.tearsStatus = 2; startQuestTimer("SpawnTearsCopies", 2000, npc, player); npc.doCast(PRESENTATION); } else if ((nowHp <= (maxHp * 0.4)) && (world.tearsStatus == 2)) { world.tearsStatus = 3; startQuestTimer("SpawnTearsCopies", 2000, npc, player); npc.doCast(PRESENTATION); } else if ((nowHp <= (maxHp * 0.2)) && (world.tearsStatus == 3)) { world.tearsStatus = 4; startQuestTimer("SpawnTearsCopies", 2000, npc, player); npc.doCast(PRESENTATION); } else if (nowHp <= (maxHp * 0.1)) { world.isUsedInvulSkill = true; npc.setIsInvul(true); broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.IT_WILL_NOT_BE_THAT_EASY_TO_KILL_ME); } } } } else if (npc.getId() == TEARS_COPY) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { npc.getVariables().set(world.damageTracker, npc.getVariables().getInt(world.damageTracker) + damage); if (npc.getVariables().getInt(world.damageTracker) > 50000) { npc.deleteMe(); } } } return null; } @Override public String onSpellFinished(L2Npc npc, L2PcInstance player, Skill skill) { if ((npc.getId() == BAYLOR) && (skill.getId() == 5225)) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld) { ((CCWorld) tmpworld).raidStatus++; } } return super.onSpellFinished(npc, player, skill); } @Override public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { CrystalGolem cryGolem = world.crystalGolems.get(npc); if (event.equalsIgnoreCase("TeleportOut")) { teleportPlayer(player, new Location(149413, 173078, -5014), 0); } else if (event.equalsIgnoreCase("TeleportParme")) { teleportPlayer(player, new Location(153689, 142226, -9750), world.getInstanceId()); } else if (event.equalsIgnoreCase("Timer2") || event.equalsIgnoreCase("Timer3") || event.equalsIgnoreCase("Timer4") || event.equalsIgnoreCase("Timer5")) { if (player.getInstanceId() == world.getInstanceId()) { teleportPlayer(player, new Location(144653, 152606, -12126), world.getInstanceId()); player.stopSkillEffects(true, 5239); EVENT_TIMER_1.getSkill().applyEffects(player, player); startQuestTimer("Timer2", 300000, npc, player); } } else if (event.equalsIgnoreCase("Timer21") || event.equalsIgnoreCase("Timer31") || event.equalsIgnoreCase("Timer41") || event.equalsIgnoreCase("Timer51")) { InstanceManager.getInstance().getInstance(world.getInstanceId()).removeNpcs(); world.npcList2.clear(); runSteamRooms(world, STEAM1_SPAWNS, 22); startQuestTimer("Timer21", 300000, npc, null); } else if (event.equalsIgnoreCase("CheckKechiAttack")) { if (npc.isInCombat()) { startQuestTimer("SpawnGuards", SPAWN[0], npc, null); cancelQuestTimers("CheckKechiAttack"); closeDoor(DOOR4, npc.getInstanceId()); closeDoor(DOOR3, npc.getInstanceId()); } else startQuestTimer("CheckKechiAttack", 1000, npc, null); } else if (event.equalsIgnoreCase("SpawnGuards")) { world.kechisHenchmanSpawn++; world.guards.add(addSpawn(KECHIS_HENCHMAN, 153622, 149699, -12131, 56890, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153609, 149622, -12131, 64023, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153606, 149428, -12131, 64541, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153601, 149534, -12131, 64901, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153620, 149354, -12131, 1164, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153637, 149776, -12131, 61733, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153638, 149292, -12131, 64071, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153647, 149857, -12131, 59402, false, 0, false, world.getInstanceId())); world.guards.add(addSpawn(KECHIS_HENCHMAN, 153661, 149227, -12131, 65275, false, 0, false, world.getInstanceId())); if (world.kechisHenchmanSpawn <= 5) { startQuestTimer("SpawnGuards", SPAWN[world.kechisHenchmanSpawn], npc, null); } else { cancelQuestTimers("SpawnGuards"); } } else if (event.equalsIgnoreCase("EmeraldSteam")) { runEmerald(world); for (L2Npc oracle : world.oracle) { oracle.decayMe(); } } else if (event.equalsIgnoreCase("CoralGarden")) { runCoral(world); for (L2Npc oracle : world.oracle) { oracle.decayMe(); } } else if (event.equalsIgnoreCase("SpawnOracle")) { addSpawn(PARME, 153572, 142075, -9728, 10800, false, 0, false, world.getInstanceId()); addSpawn((getRandom(10) < 5 ? TREASURE_CHEST_1 : TREASURE_CHEST_2), npc.getX(), npc.getY(), npc.getZ(), npc.getHeading(), false, 0, false, world.getInstanceId()); // Baylor's Chest addSpawn(ORACLE_GUIDE_4, 153572, 142075, -12738, 10800, false, 0, false, world.getInstanceId()); cancelQuestTimer("BaylorDespawn", npc, null); cancelQuestTimers("BaylorCast"); } else if (event.equalsIgnoreCase("BaylorEffect0")) { npc.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); npc.broadcastSocialAction(1); startQuestTimer("BaylorCamera0", 11000, npc, null); startQuestTimer("BaylorEffect1", 19000, npc, null); } else if (event.equalsIgnoreCase("BaylorCamera0")) { npc.broadcastPacket(new SpecialCamera(npc, 500, -45, 170, 5000, 9000, 0, 0, 1, 0, 0)); } else if (event.equalsIgnoreCase("BaylorEffect1")) { npc.broadcastPacket(new SpecialCamera(npc, 300, 0, 120, 2000, 5000, 0, 0, 1, 0, 0)); npc.broadcastSocialAction(3); startQuestTimer("BaylorEffect2", 4000, npc, null); } else if (event.equalsIgnoreCase("BaylorEffect2")) { npc.broadcastPacket(new SpecialCamera(npc, 747, 0, 160, 2000, 3000, 0, 0, 1, 0, 0)); npc.broadcastPacket(new MagicSkillUse(npc, npc, 5402, 1, 2000, 0)); startQuestTimer("RaidStart", 2000, npc, null); } else if (event.equalsIgnoreCase("BaylorMinions")) { for (int i = 0; i < 10; i++) { int radius = 300; int x = (int) (radius * Math.cos(i * 0.618)); int y = (int) (radius * Math.sin(i * 0.618)); L2Npc mob = addSpawn(CRYSTAL_PRISON_GUARD, 153571 + x, 142075 + y, -12737, 0, false, 0, false, world.getInstanceId()); mob.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); world.animationMobs.add(mob); } startQuestTimer("BaylorEffect0", 200, npc, null); } else if (event.equalsIgnoreCase("RaidStart")) { world.camera.decayMe(); world.camera = null; npc.stopStunning(false); for (L2PcInstance p : world.raiders) { p.stopStunning(false); Throw(npc, p); if (p.getSummon() != null) { Throw(npc, p.getSummon()); } } world.raidStatus = 0; for (L2Npc mob : world.animationMobs) { mob.doDie(mob); } world.animationMobs.clear(); startQuestTimer("BaylorDespawn", 60000, npc, null, true); startQuestTimer("CheckBaylorAttack", 1000, npc, null); } else if (event.equalsIgnoreCase("CheckBaylorAttack")) { if (npc.isInCombat()) { cancelQuestTimers("CheckBaylorAttack"); startQuestTimer("BaylorAlarm", 40000, npc, null); startQuestTimer("BaylorCast", 5000, npc, null, true); world.raidStatus++; } else { startQuestTimer("CheckBaylorAttack", 1000, npc, null); } } else if (event.equalsIgnoreCase("BaylorAlarm")) { if (world.alarm == null) { int[] spawnLoc = ALARMSPAWN[getRandom(ALARMSPAWN.length)]; npc.addSkill(PHYSICAL_UP.getSkill()); npc.addSkill(MAGICAL_UP.getSkill()); world.alarm = addSpawn(ALARM, spawnLoc[0], spawnLoc[1], spawnLoc[2], 10800, false, 0, false, world.getInstanceId()); world.alarm.disableCoreAI(true); world.alarm.setIsImmobilized(true); world.alarm.broadcastPacket(new CreatureSay(world.alarm.getObjectId(), 1, world.alarm.getName(), NpcStringId.AN_ALARM_HAS_BEEN_SET_OFF_EVERYBODY_WILL_BE_IN_DANGER_IF_THEY_ARE_NOT_TAKEN_CARE_OF_IMMEDIATELY)); } } else if (event.equalsIgnoreCase("BaylorCast")) { if (world.baylor == null) { cancelQuestTimers("BaylorCast"); } else { int maxHp = npc.getMaxHp(); double nowHp = npc.getStatus().getCurrentHp(); int rand = getRandom(100); if ((nowHp < (maxHp * 0.2)) && (world.raidStatus < 3) && !npc.isAffectedBySkill(5224) && !npc.isAffectedBySkill(5225)) { if ((nowHp < (maxHp * 0.15)) && (world.raidStatus == 2)) { npc.doCast(INVINCIBLE); broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.DEMON_KING_BELETH_GIVE_ME_THE_POWER_AAAHH); } else if ((rand < 10) || (nowHp < (maxHp * 0.15))) { npc.doCast(INVINCIBLE); broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.DEMON_KING_BELETH_GIVE_ME_THE_POWER_AAAHH); startQuestTimer("BaylorSetVulnarable", 30000, world.baylor, null); } } else if ((nowHp < (maxHp * 0.3)) && (rand > 50) && !npc.isAffectedBySkill(5225) && !npc.isAffectedBySkill(5224)) { npc.doCast(BERSERK); } else if (rand < 33) { npc.setTarget(world.raiders.get(getRandom(world.raiders.size()))); npc.doCast(STRONG_PUNCH); } } } else if (event.equalsIgnoreCase("BaylorSetVulnarable")) { npc.stopSkillEffects(false, 5225); } else if (event.equalsIgnoreCase("Baylor")) { world.baylor = addSpawn(BAYLOR, 153572, 142075, -12738, 10800, false, 0, false, world.getInstanceId()); world.baylor.startStunning(); world.camera = addSpawn(29120, 153273, 141400, -12738, 10800, false, 0, false, world.getInstanceId()); world.camera.broadcastPacket(new SpecialCamera(world.camera, 700, -45, 160, 500, 15200, 0, 0, 1, 0, 0)); startQuestTimer("baylorMinions", 2000, world.baylor, null); } else if (event.equalsIgnoreCase("CheckTearsAttack")) { if (npc.isInCombat()) { closeDoor(DOOR7, npc.getInstanceId()); cancelQuestTimers("CheckTearsAttack"); } else { startQuestTimer("CheckTearsAttack", 1000, npc, null); } } else if (event.equalsIgnoreCase("SpawnTearsCopies")) { double hpStat = (npc.getStatus().getCurrentHp()) / (npc.getMaxHp()); Location tearsNewSpawnLoc = TEARS_NEW_LOCATION[getRandom(TEARS_NEW_LOCATION.length)]; npc.deleteMe(); for (int i = 0; i < 10; i++) { Location currentSpawnLoc = TEARS_NEW_LOCATION[i]; if (tearsNewSpawnLoc != currentSpawnLoc) { L2Npc copy = addSpawn(TEARS_COPY, currentSpawnLoc, false, 0, true, player.getInstanceId()); copy.setCurrentHp(copy.getMaxHp() * hpStat); copy.setIsNoRndWalk(true); ((L2Attackable) copy).addDamageHate(player, 0, 99999); world.copies.add(copy); startQuestTimer("ApplyAggressionCopies", 3000, copy, player); } else { L2Npc realTears = addSpawn(TEARS, currentSpawnLoc, false, 0, true, player.getInstanceId()); realTears.setCurrentHp(realTears.getMaxHp() * hpStat); realTears.setIsNoRndWalk(true); ((L2Attackable) realTears).addDamageHate(player, 0, 99999); startQuestTimer("ApplyAggressionTears", 3000, realTears, player); } } cancelQuestTimers("SpawnTearsCopies"); } else if (event.equalsIgnoreCase("ApplyAggressionCopies")) { npc.setRunning(); npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player); } else if (event.equalsIgnoreCase("ApplyAggressionTears")) { npc.setRunning(); npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player); cancelQuestTimers("ApplyAggressionTears"); /* * Implements Crystalline Golem */ } else if (!event.contains("Food")) { return ""; } else if (event.equalsIgnoreCase("SeekForFood1") || event.equalsIgnoreCase("SeekForFood2")) { if (world.crystalGolems.get(npc).isAtFinalDestination) { return ""; } for (L2Object object : L2World.getInstance().getVisibleObjects(npc, 300)) { if (object.isItem() && object.getInstanceId() == npc.getInstanceId() && object.getId() == CRYSTAL_FRAGMENT) { cryGolem.foodItem = (L2ItemInstance) object; if (event.equalsIgnoreCase("SeekForFood1")) { startQuestTimer("GoToFood1", 2000, npc, null); } else { startQuestTimer("GoToFood2", 2000, npc, null); } } } if (world.crystalGolems.get(npc).foodItem == null) { int rnd = getRandom(100); if (rnd < 20) { if (!cryGolem.golemHasBeenFed) { int rnd1 = getRandom(10); if (rnd1 <= 2) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.HELLO_IS_ANYONE_THERE); } else if (rnd1 > 2 && rnd1 <= 4) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.IF_SOMEONE_WOULD_GIVE_ME_SOME_OF_THOSE_TASTY_CRYSTAL_FRAGMENTS_I_WOULD_GLADLY_TELL_THEM_WHERE_TEARS_IS_HIDING_YUMMY_YUMMY); } else if (rnd1 > 4 && rnd1 <= 6) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.IS_NO_ONE_THERE_HOW_LONG_HAVE_I_BEEN_HIDING_I_HAVE_BEEN_STARVING_FOR_DAYS_AND_CANNOT_HOLD_OUT_ANYMORE); } else if (rnd1 > 6) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.HEY_YOU_FROM_ABOVE_THE_GROUND_LETS_SHARE_SOME_CRYSTAL_FRAGMENTS_IF_YOU_HAVE_ANY); } } else { int rnd2 = getRandom(5); if (rnd2 == 1) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.AH_IM_HUNGRY); } else if (rnd2 == 2) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.HOW_INSENSITIVE_ITS_NOT_NICE_TO_GIVE_ME_JUST_A_PIECE_CANT_YOU_GIVE_ME_MORE); } else if (rnd2 >= 3) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.SNIFF_SNIFF_GIVE_ME_MORE_CRYSTAL_FRAGMENTS); } } } if (event.equalsIgnoreCase("SeekForFood1")) { startQuestTimer("SeekForFood1", 2000, npc, null); } else { startQuestTimer("SeekForFood2", 2000, npc, null); } } return ""; } else if (event.equalsIgnoreCase("GoToFood1") || event.equalsIgnoreCase("GoToFood2")) { cryGolem.newLoc = new Location(cryGolem.foodItem.getX(), cryGolem.foodItem.getY(), cryGolem.foodItem.getZ(), 0); cryGolem.oldLoc = new Location(npc.getX(), npc.getY(), npc.getZ(), npc.getHeading()); npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO,cryGolem.newLoc); if (event.equalsIgnoreCase("GoToFood1")) { startQuestTimer("ReachForFood1", 2000, npc, null, true); cancelQuestTimers("GoToFood1"); } else { startQuestTimer("ReachForFood2", 2000, npc, null, true); cancelQuestTimers("GoToFood2"); } return ""; } else if (event.equalsIgnoreCase("ReachForFood1") || event.equalsIgnoreCase("ReachForFood2")) { if((!cryGolem.foodItem.isVisible()) && !(npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_REST)) { npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, cryGolem.oldLoc); if (event.equalsIgnoreCase("ReachForFood1")) { startQuestTimer("ReturnFromFood1", 2000, npc, null, true); cancelQuestTimers("ReachForFood1"); } else { startQuestTimer("ReturnFromFood2", 2000, npc, null, true); cancelQuestTimers("ReachForFood2"); } return ""; } else if (npc.calculateDistance(cryGolem.newLoc.getLocation(), false, false) == 0) { npc.getAI().setIntention(CtrlIntention.AI_INTENTION_REST); L2World.getInstance().removeVisibleObject(cryGolem.foodItem, cryGolem.foodItem.getWorldRegion()); L2World.getInstance().removeObject(cryGolem.foodItem); cryGolem.foodItem = null; int rnd3 = getRandom(10); if (!cryGolem.golemHasBeenFed) { cryGolem.golemHasBeenFed = true; } if (rnd3 <= 4) { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.YUMMY_THIS_IS_SO_TASTY); } else { broadcastNpcSay(npc, Say2.NPC_ALL, NpcStringId.CRISPY_AND_COLD_FEELING_TEEHEE_DELICIOUS); } if (npc.calculateDistance(golemFinalDestination1, false, false) < 100 && !world.golemIsAtFinalDestination1) { npc.doCast(PRESENTATION); world.golemIsAtFinalDestination1 = true; cryGolem.isAtFinalDestination = true; if (world.golemIsAtFinalDestination2) { openDoor(DOOR7, world.getInstanceId()); L2Npc tears = addSpawn(TEARS, tearsSpawnLocation, false, 0, true, world.getInstanceId()); startQuestTimer("CheckTearsAttack", 1000, tears, null); world.setStatus(4); } if (event.equalsIgnoreCase("ReachForFood1")) { cancelQuestTimers("ReachForFood1"); } else { cancelQuestTimers("ReachForFood2"); } } else if (npc.calculateDistance(golemFinalDestination2, false, false) < 100 && !world.golemIsAtFinalDestination2) { npc.doCast(PRESENTATION); world.golemIsAtFinalDestination2 = true; cryGolem.isAtFinalDestination = true; if (world.golemIsAtFinalDestination1) { openDoor(DOOR7, world.getInstanceId()); L2Npc tears = addSpawn(TEARS, tearsSpawnLocation, false, 0, true, world.getInstanceId()); startQuestTimer("CheckTearsAttack", 1000, tears, null); world.setStatus(4); } if (event.equalsIgnoreCase("ReachForFood1")) { cancelQuestTimers("ReachForFood1"); } else { cancelQuestTimers("ReachForFood2"); } } else if (event.equalsIgnoreCase("ReachForFood1")) { startQuestTimer("SeekForFood1", 2000, npc, null); cancelQuestTimers("ReachForFood1"); } else { startQuestTimer("SeekForFood2", 2000, npc, null); cancelQuestTimers("ReachForFood2"); } } return ""; } else if ((event.equalsIgnoreCase("ReturnFromFood1") || event.equalsIgnoreCase("ReturnFromFood2")) && (npc.calculateDistance(cryGolem.oldLoc.getLocation(), false, false) == 0)) { npc.getAI().setIntention(CtrlIntention.AI_INTENTION_REST); if (event.equalsIgnoreCase("ReturnFromFood1")) { startQuestTimer("SeekForFood1", 2000, npc, null); cancelQuestTimers("ReturnFromFood1"); } else { startQuestTimer("SeekForFood2", 2000, npc, null); cancelQuestTimers("ReturnFromFood2"); } } return ""; } return ""; } private void giveRewards(L2PcInstance player, int instanceId, int bossCry, boolean isBaylor) { final int num = Math.max(rates().getCorpseDropChanceMultiplier().intValue(), 1); L2Party party = player.getParty(); if (party != null) { for (L2PcInstance partyMember : party.getMembers()) { if (partyMember.getInstanceId() == instanceId) { if (!isBaylor && hasQuestItems(partyMember, CONTAMINATED_CRYSTAL)) { takeItems(partyMember, CONTAMINATED_CRYSTAL, 1); giveItems(partyMember, bossCry, 1); } if (getRandom(10) < 5) { giveItems(partyMember, WHITE_SEED_OF_EVIL_SHARD, num); } else { giveItems(partyMember, BLACK_SEED_OF_EVIL_SHARD, num); } } } } else if (player.getInstanceId() == instanceId) { if (!isBaylor && hasQuestItems(player, CONTAMINATED_CRYSTAL)) { takeItems(player, CONTAMINATED_CRYSTAL, 1); giveItems(player, bossCry, 1); } if (getRandom(10) < 5) { giveItems(player, WHITE_SEED_OF_EVIL_SHARD, num); } else { giveItems(player, BLACK_SEED_OF_EVIL_SHARD, num); } } } @Override public String onKill(L2Npc npc, L2PcInstance player, boolean isSummon) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { if ((world.getStatus() == 2) && world.npcList1.containsKey(npc)) { world.npcList1.put(npc, true); for (boolean isDead : world.npcList1.values()) { if (!isDead) { return ""; } } world.setStatus(3); CrystalGolem crygolem1 = new CrystalGolem(); CrystalGolem crygolem2 = new CrystalGolem(); L2Npc golem1 = addSpawn(CRYSTALLINE_GOLEM, 140547, 151670, -11813, 32767, false, 0, false, world.getInstanceId()); startQuestTimer("SeekForFood1", 2000, golem1, null); golem1.setRunning(); world.crystalGolems.put(golem1, crygolem1); L2Npc golem2 = addSpawn(CRYSTALLINE_GOLEM, 141941, 151684, -11813, 63371, false, 0, false, world.getInstanceId()); startQuestTimer("SeekForFood2", 2000, golem2, null); golem2.setRunning(); world.crystalGolems.put(golem2, crygolem2); } else if ((world.getStatus() == 4) && (npc.getId() == TEARS)) { InstanceManager.getInstance().getInstance(world.getInstanceId()).setDuration(300000); addSpawn(ORACLE_GUIDE_3, 144312, 154420, -11855, 0, false, 0, false, world.getInstanceId()); giveRewards(player, npc.getInstanceId(), CLEAR_CRYSTAL, false); } else if ((world.getStatus() == 2) && world.keyKeepers.contains(npc)) { if (npc.getId() == GATEKEEPER_LOHAN) { npc.dropItem(player, BLUE_CORAL_KEY, 1); runEmeraldSquare(world); } else if (npc.getId() == GATEKEEPER_PROVO) { npc.dropItem(player, RED_CORAL_KEY, 1); runSteamRooms(world, STEAM1_SPAWNS, 22); Optional.ofNullable(player.getParty()).map(L2Party::getMembers).orElseGet(() -> List.of(player)).stream() .filter(member -> member.getInstanceId() == world.getInstanceId()) .forEach(member -> { EVENT_TIMER_1.getSkill().applyEffects(member, member); startQuestTimer("Timer2", 300000, npc, member); }); startQuestTimer("Timer21", 300000, npc, null); } for (L2Npc gk : world.keyKeepers) { if (gk != npc) { gk.decayMe(); } } } else if (world.getStatus() == 3) { if (checkKillProgress(0, npc, world)) { world.setStatus(4); addSpawn(TOURMALINE, 148202, 144791, -12235, 0, false, 0, false, world.getInstanceId()); } else { return ""; } } else if (world.getStatus() == 4) { if (npc.getId() == TOURMALINE) { world.setStatus(5); addSpawn(TEROD, 147777, 146780, -12281, 0, false, 0, false, world.getInstanceId()); } } else if (world.getStatus() == 5) { if (npc.getId() == TEROD) { world.setStatus(6); addSpawn(TOURMALINE, 143694, 142659, -11882, 0, false, 0, false, world.getInstanceId()); } } else if (world.getStatus() == 6) { if (npc.getId() == TOURMALINE) { world.setStatus(7); addSpawn(DOLPH, 142054, 143288, -11825, 0, false, 0, false, world.getInstanceId()); } } else if (world.getStatus() == 7) { if (npc.getId() == DOLPH) { world.setStatus(8); // first door opener trap L2Npc trap = addTrap(DOOR_OPENING_TRAP[0], DOOR_OPENING_TRAP[1], DOOR_OPENING_TRAP[2], DOOR_OPENING_TRAP[3], DOOR_OPENING_TRAP[4], null, world.getInstanceId()); broadcastNpcSay(trap, Say2.NPC_SHOUT, NpcStringId.YOU_HAVE_FINALLY_COME_HERE_BUT_YOU_WILL_NOT_BE_ABLE_TO_FIND_THE_SECRET_ROOM); } } else if (world.getStatus() == 8) { for (int i = 0; i < 4; i++) { if ((world.roomsStatus[i] == 1) && checkKillProgress(i + 1, npc, world)) { world.roomsStatus[i] = 2; } if (world.roomsStatus[i] == 2) { world.cleanedRooms++; if (world.cleanedRooms == 21) { runDarnel(world); } } } } else if ((world.getStatus() >= 22) && (world.getStatus() <= 25)) { if (npc.getId() == 22416) { for (L2Npc oracle : world.oracles.keySet()) { if (world.oracles.get(oracle) == npc) { world.oracles.put(oracle, null); } } } if (checkKillProgress(0, npc, world)) { world.npcList2.clear(); int[][] oracleOrder; switch (world.getStatus()) { case 22: closeDoor(DOOR6, npc.getInstanceId()); oracleOrder = ordreOracle1; break; case 23: oracleOrder = ordreOracle2; break; case 24: oracleOrder = ordreOracle3; break; case 25: world.setStatus(26); Optional.ofNullable(player.getParty()).map(L2Party::getMembers).orElseGet(() -> List.of(player)) .forEach(member -> member.stopSkillEffects(true, 5239)); cancelQuestTimers("Timer5"); cancelQuestTimers("Timer51"); openDoor(DOOR3, npc.getInstanceId()); openDoor(DOOR4, npc.getInstanceId()); L2Npc kechi = addSpawn(KECHI, 154069, 149525, -12158, 51165, false, 0, false, world.getInstanceId()); startQuestTimer("CheckKechiAttack", 1000, kechi, null); return ""; default: _log.warning("CrystalCavern-SteamCorridor: status " + world.getStatus() + " error. OracleOrder not found in " + world.getInstanceId()); return ""; } runSteamOracles(world, oracleOrder); } } else if (((world.getStatus() == 9) && (npc.getId() == DARNEL)) || ((world.getStatus() == 26) && (npc.getId() == KECHI))) { InstanceManager.getInstance().getInstance(world.getInstanceId()).setDuration(300000); int bossCry; if (npc.getId() == KECHI) { bossCry = RED_CRYSTAL; cancelQuestTimers("SpawnGuards"); addSpawn(ORACLE_GUIDE_3, 154077, 149527, -12159, 0, false, 0, false, world.getInstanceId()); } else if (npc.getId() == DARNEL) { bossCry = BLUE_CRYSTAL; addSpawn(ORACLE_GUIDE_3, 152761, 145950, -12588, 0, false, 0, false, world.getInstanceId()); } else { // something is wrong return ""; } giveRewards(player, npc.getInstanceId(), bossCry, false); } if (npc.getId() == ALARM) { world.baylor.removeSkill(PHYSICAL_UP.getSkillId()); world.baylor.removeSkill(MAGICAL_UP.getSkillId()); world.alarm = null; if ((world.baylor.getMaxHp() * 0.3) < world.baylor.getStatus().getCurrentHp()) { startQuestTimer("BaylorAlarm", 40000, world.baylor, null); } } else if (npc.getId() == BAYLOR) { world.setStatus(31); world.baylor = null; Instance baylorInstance = InstanceManager.getInstance().getInstance(npc.getInstanceId()); baylorInstance.setDuration(300000); this.startQuestTimer("SpawnOracle", 1000, npc, null); giveRewards(player, npc.getInstanceId(), -1, true); } } return ""; } @Override public String onTalk(L2Npc npc, L2PcInstance player) { int npcId = npc.getId(); QuestState st = getQuestState(player, false); if (st == null) { st = newQuestState(player); } if (npcId == ORACLE_GUIDE_1) { enterInstance(player, new CCWorld(System.currentTimeMillis() + 5400000), "CrystalCaverns.xml", TEMPLATE_ID); return ""; } InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(npc.getInstanceId()); if (tmpworld instanceof CCWorld world) { if ((npc.getId() >= ORACLE_GUIDE_5) && (npc.getId() <= ORACLE_GUIDE_6) && world.oracleTriggered[npc.getId() - ORACLE_GUIDE_5]) { boolean doTeleport = false; Location loc = null; L2Party party = player.getParty(); doTeleport = true; switch (npc.getId()) { case ORACLE_GUIDE_5: if (world.getStatus() == 22) { runSteamRooms(world, STEAM2_SPAWNS, 23); } loc = new Location(147529, 152587, -12169); cancelQuestTimers("Timer2"); cancelQuestTimers("Timer21"); Optional.ofNullable(player.getParty()).map(L2Party::getMembers).orElseGet(() -> List.of(player)).stream() .filter(member -> member.getInstanceId() == world.getInstanceId()) .forEach(member -> { member.stopSkillEffects(true, 5239); EVENT_TIMER_2.getSkill().applyEffects(member, member); startQuestTimer("Timer3", 600000, npc, member); }); startQuestTimer("Timer31", 600000, npc, null); break; case ORACLE_GUIDE_8: if (world.getStatus() == 23) { runSteamRooms(world, STEAM3_SPAWNS, 24); } loc = new Location(150194, 152610, -12169); cancelQuestTimers("Timer3"); cancelQuestTimers("Timer31"); if (party != null) { for (L2PcInstance partyMember : party.getMembers()) { if (partyMember.getInstanceId() == world.getInstanceId()) { partyMember.stopSkillEffects(true, 5239); EVENT_TIMER_4.getSkill().applyEffects(partyMember, partyMember); startQuestTimer("Timer4", 1200000, npc, partyMember); } } } else { player.stopSkillEffects(true, 5239); EVENT_TIMER_4.getSkill().applyEffects(player, player); startQuestTimer("Timer4", 1200000, npc, player); } startQuestTimer("Timer41", 1200000, npc, null); break; case ORACLE_GUIDE_6: if (world.getStatus() == 24) { runSteamRooms(world, STEAM4_SPAWNS, 25); } loc = new Location(149743, 149986, -12141); cancelQuestTimers("Timer4"); cancelQuestTimers("Timer41"); if (party != null) { for (L2PcInstance partyMember : party.getMembers()) { if (partyMember.getInstanceId() == world.getInstanceId()) { partyMember.stopSkillEffects(true, 5239); EVENT_TIMER_3.getSkill().applyEffects(partyMember, partyMember); startQuestTimer("Timer5", 900000, npc, partyMember); } } } else { player.stopSkillEffects(true, 5239); EVENT_TIMER_3.getSkill().applyEffects(player, player); startQuestTimer("Timer5", 900000, npc, player); } startQuestTimer("Timer51", 900000, npc, null); break; default: // something is wrong doTeleport = false; } if (doTeleport && (loc != null)) { if (!checkOracleConditions(player)) { return ""; } else if (party != null) { for (L2PcInstance partyMember : party.getMembers()) { partyMember.destroyItemByItemId("Quest", RED_CORAL, 1, player, true); teleportPlayer(partyMember, loc, npc.getInstanceId()); } } else { teleportPlayer(player, loc, npc.getInstanceId()); } } } else if (npc.getId() == ORACLE_GUIDE_3) { if ((world.getStatus() < 30) && checkBaylorConditions(player)) { world.raiders.clear(); world.raiders.addAll(Optional.ofNullable(player.getParty()).map(L2Party::getMembers).orElseGet(() -> List.of(player))); } else { return ""; } world.setStatus(30); long time = world.endTime - System.currentTimeMillis(); Instance baylorInstance = InstanceManager.getInstance().getInstance(world.getInstanceId()); baylorInstance.setDuration((int) time); int radius = 150; int i = 0; int members = world.raiders.size(); for (L2PcInstance p : world.raiders) { int x = (int) (radius * Math.cos((i * 2 * Math.PI) / members)); int y = (int) (radius * Math.sin((i++ * 2 * Math.PI) / members)); p.teleToLocation(new Location(153571 + x, 142075 + y, -12737)); L2Summon pet = p.getSummon(); if (pet != null) { pet.teleToLocation(new Location(153571 + x, 142075 + y, -12737), true); pet.broadcastPacket(new ValidateLocation(pet)); } p.startStunning(); p.broadcastPacket(new ValidateLocation(p)); } startQuestTimer("Baylor", 30000, npc, null); } else if ((npc.getId() == ORACLE_GUIDE_4) && (world.getStatus() == 31)) { teleportPlayer(player, new Location(153522, 144212, -9747), npc.getInstanceId()); } } return ""; } @Override public String onTrapAction(L2TrapInstance trap, L2Character trigger, TrapAction action) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(trap.getInstanceId()); if (tmpworld instanceof CCWorld world) { switch (action) { case TRAP_DISARMED: if (trap.getId() == DOOR_OPENING_TRAP[0]) { openDoor(DOOR14, world.getInstanceId()); runEmeraldRooms(world, ROOM1_SPAWNS, 1); } break; } } return null; } @Override public String onEnterZone(L2Character character, L2ZoneType zone) { if (character instanceof L2PcInstance) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(character.getInstanceId()); if (tmpworld instanceof CCWorld world) { if (world.getStatus() == 8) { int room; int[][] spawns; switch (zone.getId()) { case 20105: spawns = ROOM2_SPAWNS; room = 2; break; case 20106: spawns = ROOM3_SPAWNS; room = 3; break; case 20107: spawns = ROOM4_SPAWNS; room = 4; break; default: return super.onEnterZone(character, zone); } for (L2DoorInstance door : InstanceManager.getInstance().getInstance(world.getInstanceId()).getDoors()) { if (door.getId() == (room + DOOR10)) { if (door.getOpen()) { return ""; } if (!hasQuestItems((L2PcInstance) character, SECRET_KEY)) { return ""; } if (world.roomsStatus[zone.getId() - 20104] == 0) { runEmeraldRooms(world, spawns, room); } door.openMe(); takeItems((L2PcInstance) character, SECRET_KEY, 1); world.openedDoors.put(door, (L2PcInstance) character); break; } } } } } return super.onEnterZone(character, zone); } @Override public String onExitZone(L2Character character, L2ZoneType zone) { if (character instanceof L2PcInstance) { InstanceWorld tmpworld = InstanceManager.getInstance().getWorld(character.getInstanceId()); if (tmpworld instanceof CCWorld world) { if (world.getStatus() == 8) { int doorId; switch (zone.getId()) { case 20105: doorId = DOOR11; break; case 20106: doorId = DOOR12; break; case 20107: doorId = DOOR13; break; default: return super.onExitZone(character, zone); } for (L2DoorInstance door : InstanceManager.getInstance().getInstance(world.getInstanceId()).getDoors()) { if (door.getId() == doorId) { if (door.getOpen() && (world.openedDoors.get(door) == character)) { door.closeMe(); world.openedDoors.remove(door); } break; } } } } } return super.onExitZone(character, zone); } }
  2. The people that are killing L2JServer must be publicly exposed. I've shared with you Improved Crystal Caverns and Precision Formula. In return all I received was disrespect and humiliation? Well, that was the last of me for the true open source L2JServer. Have fun copycats!
  3. @Override public void addDamage(Creature attacker, int damage, Skill skill) { super.addDamage(attacker, damage, skill); getAI().startFollow(attacker); addDamageHate(attacker, 0, 10); World.getInstance().forEachVisibleObjectInRange(this, GuardInstance.class, 500, guard -> { guard.getAI().startFollow(attacker); guard.addDamageHate(attacker, 0, 10); }); } I believe here is the part where you should work on. Maybe could look into addDamage method.
  4. Oh I think I got it now. Its related to rouge skill "Provoke" and a minions that follow main monster. Its a famous bug among L2J packs. :d Well there is many ways you can approach this, first have you determined its not clan range related by having 2 groups of same clan at close range and see if other group get aggro.
  5. Its a C5 Boss then, I could have mistaken. Here is some info you can gather. https://legacylineage2.fandom.com/wiki/Updates_-_C5_-_Monsters https://lineage.pmfun.com/list/c5c6
  6. Did you verify if the specific npc is type of GuardInstance? You can do that by finding it by ID in xml data stats. More details could be helpful, are you referring town guards?
  7. Of coarse it existed on interlude. Its a C4 boss if i'm not mistaking. Of what I remember back in the days it was not instanced and can be fought once for the whole server until next respawn which is date+window.
  8. They all pretty much the same when it comes to edit. It all depends to what extend you need edit. Maps are hard to mod in all clients. Interlude is easiest to mod.
  9. You should first use a method to check if player has enough adena and return message if insufficient. Then at end of script another method should consume(remove) the adena and return message about the adena consumption. You should do that for each option separately. If u want it more complex than that. You should create a config file and use a boolean to enable feature and string for adena amount per option.
  10. Indeed L2J needs to be rewritten from the bones. But I can say out of experience those "L2OFF" platforms and extenders that claim to be PTS leak also have bugs and you won't be able to find a source other than decompiled, making it a lot harder to work with, on top of all they are heavier on resources. The true benefit of "OFF" platform would be if you run highly populated low rate server with minimum custom features. While JAVA platform is suitable for customizing game-play to unlimited extend (maybe client).
  11. AMD is the INVENTOR. INTEL is SUCCESSOR. same goes for Radeon and Nvidia. AMD will always have better performance even tho their top products are unavailable for the general consumer. INTEL is famous with longevity but fairly unrelative in the age we live. Regardless that most of my systems run on INTEL. My vote goes for AMD.
  12. Here you go. You can change it into double and push to main branch. I have already asked for more appropriate way to present my work. What if is ego? Say I've "learned" java, got familiar with project enough to fix a broken drop calc, present for many years, with close to none assistance and I have shared it, if not for money, what's left? If you can not appreciate my effort to give it few bytes of credits that is not being compiled, then users should apply patch manually on demand, found here. After all, this is a custom feature for a custom drop on a custom rate and L2JServer focuses on "Retail" behavior and code does not take part of main branch. /* * Copyright © 2004-2021 L2J Server * * This file is part of L2J Server. * * L2J Server 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. * * L2J Server 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 <http://www.gnu.org/licenses/>. */ package com.l2jserver.gameserver.model.drops.strategy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.l2jserver.commons.util.Rnd; import com.l2jserver.gameserver.model.actor.L2Character; import com.l2jserver.gameserver.model.drops.GeneralDropItem; import com.l2jserver.gameserver.model.drops.GroupedGeneralDropItem; import com.l2jserver.gameserver.model.drops.IDropItem; import com.l2jserver.gameserver.model.holders.ItemHolder; /** *@author Battlecruiser, Cherish */ public interface IGroupedItemDropCalculationStrategy { /** * L2J Server most percise drop calculation when group chances are over one houdred percent. */ IGroupedItemDropCalculationStrategy DEFAULT_STRATEGY = new IGroupedItemDropCalculationStrategy() { private final Map<GroupedGeneralDropItem, GeneralDropItem> singleItemCache = new ConcurrentHashMap<>(); private GeneralDropItem getSingleItem(GroupedGeneralDropItem dropItem) { final GeneralDropItem item1 = dropItem.getItems().iterator().next(); singleItemCache.putIfAbsent(dropItem, new GeneralDropItem(item1.getItemId(), item1.getMin(), item1.getMax(), (item1.getChance() * dropItem.getChance()) / 100, // item1.getAmountStrategy(), item1.getChanceStrategy(), dropItem.getPreciseStrategy(), dropItem.getKillerChanceModifierStrategy(), item1.getDropCalculationStrategy())); return singleItemCache.get(dropItem); } @Override public List<ItemHolder> calculateDrops(GroupedGeneralDropItem dropItem, L2Character victim, L2Character killer) { if (dropItem.getItems().size() == 1) { return getSingleItem(dropItem).calculateDrops(victim, killer); } GroupedGeneralDropItem normalized = dropItem.normalizeMe(victim, killer); if (normalized.getChance() > (Rnd.nextDouble() * 100)) { final double random = (Rnd.nextDouble() * 100); double totalChance = 0; for (GeneralDropItem item2 : normalized.getItems()) { totalChance += item2.getChance(); if (totalChance > random) { int amountMultiply = 1; if (dropItem.isPreciseCalculated() && normalized.getChance() > 100) { int MostPreciseFormula = 0; MostPreciseFormula += item2.getChance() * (normalized.getChance() / 100); if (MostPreciseFormula >= 100) { amountMultiply = (int) MostPreciseFormula / 100; if ((MostPreciseFormula % 100) > (Rnd.nextDouble() * 100)) { amountMultiply++; } } } return Collections.singletonList(new ItemHolder(item2.getItemId(), Rnd.get(item2.getMin(victim), item2.getMax(victim)) * amountMultiply)); } } } return null; } }; /** * This strategy calculates a group's drop by calculating drops of its individual items and merging its results. */ IGroupedItemDropCalculationStrategy DISBAND_GROUP = (item, victim, killer) -> { List<ItemHolder> dropped = new ArrayList<>(); for (IDropItem dropItem : item.extractMe()) { dropped.addAll(dropItem.calculateDrops(victim, killer)); } return dropped.isEmpty() ? null : dropped; }; /** * This strategy when group has precise calculation rolls multiple times over group to determine drops when group's chance raises over 100% instead of just multiplying the dropped item's amount. Thus it can produce different items from group at once. */ IGroupedItemDropCalculationStrategy PRECISE_MULTIPLE_GROUP_ROLLS = (item, victim, killer) -> { if (!item.isPreciseCalculated()) { // if item hasn't precise calculation there's no change from DEFAULT_STRATEGY return DEFAULT_STRATEGY.calculateDrops(item, victim, victim); } GroupedGeneralDropItem newItem = new GroupedGeneralDropItem(item.getChance(), DEFAULT_STRATEGY, item.getKillerChanceModifierStrategy(), IPreciseDeterminationStrategy.NEVER); newItem.setItems(item.getItems()); GroupedGeneralDropItem normalized = newItem.normalizeMe(victim, killer); // Let's determine the number of rolls. int rolls = (int) (normalized.getChance() / 100); if ((Rnd.nextDouble() * 100) < (normalized.getChance() % 100)) { rolls++; } List<ItemHolder> dropped = new ArrayList<>(rolls); for (int i = 0; i < rolls; i++) { // As further normalizing on already normalized drop group does nothing, we can just pass the calculation to DEFAULT_STRATEGY with precise calculation disabled as we handle it. dropped.addAll(normalized.calculateDrops(victim, killer)); } return dropped.isEmpty() ? null : dropped; }; List<ItemHolder> calculateDrops(GroupedGeneralDropItem item, L2Character victim, L2Character killer); }
  13. I found this over a quick lookup but never tested. Any idea what it does?
  14. You guys might as well share a patch or patched version of this release. Someone may find it useful. Instead of knock his head on the wall.
  15. this dude probably haven't installed db properly. don't know of how this source got here but any great share deserves appreciation for all and everybody's effort.
  16. Of coarse you can have them live and they are very stable. Why I wouldn't recommend them for live project (unless is Beta) is because of missing features. Architecture wise yes. Java++. Those are best to learn on.
  17. @Nightw0lf Yes lately some randoms got in control over l2jserver, but is the leader that give them the privilege to do whatever they want. I'm not gonna dive into discussing them, they don't really matter. Overall L2JServer is good project and maintained professional structure. Has very large base and support for more recent java++. @LordWinter No offense, I really enjoyed your project on the test server. Personally have referred it to some people that needed a ready to go pack. If I had money to spare I would have purchased it and you know that.
  18. Stackable items is not traceable as equipment, there admin need to find by logs. but as said logs can be easily filtered and transactions become more visible. It all comes down to admin if he wants or know how to find you. [INFO ] 2021-01-08 22:43:20 item: CHANGED Adena(57)[268525608] amount 1250693297 by Fastkill [268519867], referenced by MecanOtGorata [268504804]. [INFO ] 2020-12-31 04:40:35 item: SET_OWNER Earring of Zaken(6659)[268488091] +3 by Fastkill [268519867], referenced by Bingo [268522796]. [INFO ] 2020-12-31 04:40:35 item: SET_OWNER Earring of Zaken(6659)[268557436] +10 by Bingo [268522796], referenced by Fastkill [268519867]. [INFO ] 2020-12-31 04:45:51 item: SET_OWNER Pirate Hat(8922)[268489882] by Bingo [268522796], referenced by MecanOtGorata [268504804]. here is L2J example
  19. Never mind @LordWinter, seems I got confused. Please accept my apologies.
  20. Guys, every item that is being generated in DB has unique ID bound only to this specific item. Admins don't even bother tracing transactions. They can find it among all other item data. Regardless, depending on what filters admin apply, item transactions will be very visible in logs. If admin wants to find it and he has the skills to do it, he will.
  21. Nowhere have been stated to be private, leader is main branch representative. I'm just a regular member. L2JEternity commit revision 2092 March 17, 2021 @LordWinter L2JSunrise commit revision 1091 April 18, 2021 @`NeverMore
×
×
  • Create New...