package server.maps; import clientside.MapleBuffStat; import clientside.MapleCharacter; import clientside.MapleClient; import clientside.MonsterFamiliar; import client.inventory.Equip; import client.inventory.Item; import client.inventory.MapleInventoryType; import client.inventory.MaplePet; import client.status.MonsterStatus; import client.status.MonsterStatusEffect; import constants.GameConstants; import constants.TutorialConstants; import database.DatabaseConnection; import handling.channel.ChannelServer; import handling.world.PartyOperation; import handling.world.World; import handling.world.exped.ExpeditionType; import java.awt.Point; import java.awt.Rectangle; import java.lang.ref.WeakReference; import java.sql.Connection; import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import scripting.EventManager; import server.MapleCarnivalFactory; import server.MapleInventoryManipulator; import server.MapleItemInformationProvider; import server.MaplePVP; import server.MaplePortal; import server.MapleSquad; import server.MapleSquad.MapleSquadType; import server.MapleStatEffect; import server.Randomizer; import server.SpeedRunner; import server.Timer; import server.Timer.MapTimer; import server.life.MapleLifeFactory; import server.life.MapleMonster; import server.life.MapleMonsterInformationProvider; import server.life.MapleNPC; import server.life.MonsterDropEntry; import server.life.MonsterGlobalDropEntry; import server.life.SpawnPoint; import server.life.SpawnPointAreaBoss; import server.life.Spawns; import static server.quest.MapleQuestRequirementType.mob; import tools.FileoutputUtil; import tools.Pair; import tools.StringUtil; import tools.packet.CField; import tools.packet.CField.SummonPacket; import tools.packet.CWvsContext; import tools.packet.MobPacket; import tools.packet.PetPacket; public final class MapleMap { private final Map<MapleMapObjectType, LinkedHashMap<Integer, MapleMapObject>> mapobjects; private final Map<MapleMapObjectType, ReentrantReadWriteLock> mapobjectlocks; private final List<MapleCharacter> characters = new ArrayList(); private final ReentrantReadWriteLock charactersLock = new ReentrantReadWriteLock(); private int runningOid = 500000; private final Lock runningOidLock = new ReentrantLock(); private final List<Spawns> monsterSpawn = new ArrayList(); private final AtomicInteger spawnedMonstersOnMap = new AtomicInteger(0); private final Map<Integer, MaplePortal> portals = new HashMap(); private MapleFootholdTree footholds = null; private float monsterRate; private float recoveryRate; private MapleMapEffect mapEffect; private WeakReference<MapleCharacter> changeMobOrigin = null; private byte channel; protected MapleClient c; private short decHP = 0; private short createMobInterval = 9000; private short top = 0; private short bottom = 0; private short left = 0; private short right = 0; private int consumeItemCoolTime = 0; private int protectItem = 0; private int decHPInterval = 10000; private int mapid; private int returnMapId; private int timeLimit; private boolean muted; private int fieldLimit; private int maxRegularSpawn = 0; private int fixedMob; private int forcedReturnMap = 999999999; private int instanceid = -1; private int lvForceMove = 0; private int lvLimit = 0; private int permanentWeather = 0; private int partyBonusRate = 0; private boolean town; private boolean clock; private boolean personalShop; private boolean everlast = false; private boolean dropsDisabled = false; private boolean gDropsDisabled = false; private boolean soaring = false; private boolean squadTimer = false; private boolean isSpawns = true; private boolean checkStates = true; private String mapName; private String streetName; private String onUserEnter; private String onFirstUserEnter; private String speedRunLeader = ""; private List<Integer> dced = new ArrayList(); private ScheduledFuture<?> squadSchedule; private long speedRunStart = 0L; private long lastSpawnTime = 0L; private long lastHurtTime = 0L; private MapleNodes nodes; private MapleSquad.MapleSquadType squad; private Map<String, Integer> environment = new LinkedHashMap(); public MapleMap(int mapid, int channel, int returnMapId, float monsterRate) { this.mapid = mapid; this.channel = ((byte) channel); this.returnMapId = returnMapId; if (this.returnMapId == 999999999) { this.returnMapId = mapid; } if (GameConstants.getPartyPlay(mapid) > 0) { this.monsterRate = ((monsterRate - 1.0F) * 2.5F + 1.0F); } else { this.monsterRate = monsterRate; } EnumMap objsMap = new EnumMap(MapleMapObjectType.class); EnumMap objlockmap = new EnumMap(MapleMapObjectType.class); for (MapleMapObjectType type : MapleMapObjectType.values()) { objsMap.put(type, new LinkedHashMap()); objlockmap.put(type, new ReentrantReadWriteLock()); } this.mapobjects = Collections.unmodifiableMap(objsMap); this.mapobjectlocks = Collections.unmodifiableMap(objlockmap); } public Collection<MapleCharacter> getNearestPvpChar(Point attacker, double maxRange, double maxHeight, Collection<MapleCharacter> chr) { Collection<MapleCharacter> character = new LinkedList<MapleCharacter>(); for (MapleCharacter a : characters) { if (chr.contains(a.getClient().getPlayer())) { Point attackedPlayer = a.getPosition(); MaplePortal Port = a.getMap().findClosestSpawnpoint(a.getPosition()); Point nearestPort = Port.getPosition(); double safeDis = attackedPlayer.distance(nearestPort); double distanceX = attacker.distance(attackedPlayer.getX(), attackedPlayer.getY()); if (MaplePVP.isLeft) { if (attacker.x > attackedPlayer.x && distanceX < maxRange && distanceX > 2 && attackedPlayer.y >= attacker.y - maxHeight && attackedPlayer.y <= attacker.y + maxHeight && safeDis > 2) { character.add(a); } } if (MaplePVP.isRight) { if (attacker.x < attackedPlayer.x && distanceX < maxRange && distanceX > 2 && attackedPlayer.y >= attacker.y - maxHeight && attackedPlayer.y <= attacker.y + maxHeight && safeDis > 2) { character.add(a); } } } } return character; } public final void setSpawns(boolean fm) { this.isSpawns = fm; } public final boolean getSpawns() { return this.isSpawns; } public final void setFixedMob(int fm) { this.fixedMob = fm; } public final void setForceMove(int fm) { this.lvForceMove = fm; } public final int getForceMove() { return this.lvForceMove; } public final void setLevelLimit(int fm) { this.lvLimit = fm; } public final int getLevelLimit() { return this.lvLimit; } public final void setReturnMapId(int rmi) { this.returnMapId = rmi; } public final void setSoaring(boolean b) { this.soaring = b; } public final boolean canSoar() { return this.soaring; } public final void toggleDrops() { this.dropsDisabled = (!this.dropsDisabled); } public final void setDrops(boolean b) { this.dropsDisabled = b; } public final void toggleGDrops() { this.gDropsDisabled = (!this.gDropsDisabled); } public final int getId() { return this.mapid; } public final MapleMap getReturnMap() { return ChannelServer.getInstance(this.channel).getMapFactory().getMap(this.returnMapId); } public final int getReturnMapId() { return this.returnMapId; } public final int getForcedReturnId() { return this.forcedReturnMap; } public final MapleMap getForcedReturnMap() { return ChannelServer.getInstance(this.channel).getMapFactory().getMap(this.forcedReturnMap); } public final void setForcedReturnMap(int map) { this.forcedReturnMap = map; } public final float getRecoveryRate() { return this.recoveryRate; } public final void setRecoveryRate(float recoveryRate) { this.recoveryRate = recoveryRate; } public final int getFieldLimit() { return this.fieldLimit; } public final void setFieldLimit(int fieldLimit) { this.fieldLimit = fieldLimit; } public final void setCreateMobInterval(short createMobInterval) { this.createMobInterval = createMobInterval; } public final void setTimeLimit(int timeLimit) { this.timeLimit = timeLimit; } public final void setMapName(String mapName) { this.mapName = mapName; } public final String getMapName() { return this.mapName; } public final String getStreetName() { return this.streetName; } public final void setFirstUserEnter(String onFirstUserEnter) { this.onFirstUserEnter = onFirstUserEnter; } public final void setUserEnter(String onUserEnter) { this.onUserEnter = onUserEnter; } public final String getFirstUserEnter() { return this.onFirstUserEnter; } public final String getUserEnter() { return this.onUserEnter; } public final boolean hasClock() { return this.clock; } public final void setClock(boolean hasClock) { this.clock = hasClock; } public final boolean isTown() { return this.town; } public final void setTown(boolean town) { this.town = town; } public final boolean allowPersonalShop() { return this.personalShop; } public final void setPersonalShop(boolean personalShop) { this.personalShop = personalShop; } public final void setStreetName(String streetName) { this.streetName = streetName; } public final void setEverlast(boolean everlast) { this.everlast = everlast; } public final boolean getEverlast() { return this.everlast; } public final int getHPDec() { return this.decHP; } public final void setHPDec(int delta) { if ((delta > 0) || (this.mapid == 749040100)) { this.lastHurtTime = System.currentTimeMillis(); } this.decHP = ((short) delta); } public final int getHPDecInterval() { return this.decHPInterval; } public final void setHPDecInterval(int delta) { this.decHPInterval = delta; } public final int getHPDecProtect() { return this.protectItem; } public final void setHPDecProtect(int delta) { this.protectItem = delta; } public final int getCurrentPartyId() { this.charactersLock.readLock().lock(); try { Iterator ltr = this.characters.iterator(); while (ltr.hasNext()) { MapleCharacter chr = (MapleCharacter) ltr.next(); if (chr.getParty() != null) { return chr.getParty().getId(); } } } finally { this.charactersLock.readLock().unlock(); } return -1; } public final void addMapObject(MapleMapObject mapobject) { this.runningOidLock.lock(); int newOid; try { newOid = ++this.runningOid; } finally { this.runningOidLock.unlock(); } mapobject.setObjectId(newOid); ((ReentrantReadWriteLock) this.mapobjectlocks.get(mapobject.getType())).writeLock().lock(); try { ((LinkedHashMap) this.mapobjects.get(mapobject.getType())).put(Integer.valueOf(newOid), mapobject); } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(mapobject.getType())).writeLock().unlock(); } } private void spawnAndAddRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery) { addMapObject(mapobject); this.charactersLock.readLock().lock(); try { Iterator itr = this.characters.iterator(); while (itr.hasNext()) { MapleCharacter chr = (MapleCharacter) itr.next(); if ((!chr.isClone()) && ((mapobject.getType() == MapleMapObjectType.MIST) || (chr.getTruePosition().distanceSq(mapobject.getTruePosition()) <= GameConstants.maxViewRangeSq()))) { packetbakery.sendPackets(chr.getClient()); chr.addVisibleMapObject(mapobject); } } } finally { this.charactersLock.readLock().unlock(); } } public final void removeMapObject(MapleMapObject obj) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(obj.getType())).writeLock().lock(); try { ((LinkedHashMap) this.mapobjects.get(obj.getType())).remove(Integer.valueOf(obj.getObjectId())); } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(obj.getType())).writeLock().unlock(); } } public final Point calcPointBelow(Point initial) { MapleFoothold fh = this.footholds.findBelow(initial); if (fh == null) { return null; } int dropY = fh.getY1(); if ((!fh.isWall()) && (fh.getY1() != fh.getY2())) { double s1 = Math.abs(fh.getY2() - fh.getY1()); double s2 = Math.abs(fh.getX2() - fh.getX1()); if (fh.getY2() < fh.getY1()) { dropY = fh.getY1() - (int) (Math.cos(Math.atan(s2 / s1)) * (Math.abs(initial.x - fh.getX1()) / Math.cos(Math.atan(s1 / s2)))); } else { dropY = fh.getY1() + (int) (Math.cos(Math.atan(s2 / s1)) * (Math.abs(initial.x - fh.getX1()) / Math.cos(Math.atan(s1 / s2)))); } } return new Point(initial.x, dropY); } public final Point calcDropPos(Point initial, Point fallback) { Point ret = calcPointBelow(new Point(initial.x, initial.y - 50)); if (ret == null) { return fallback; } return ret; } private void dropFromMonster(MapleCharacter chr, MapleMonster mob, boolean instanced) { if (mob == null || chr == null || ChannelServer.getInstance(channel) == null || dropsDisabled || mob.dropsDisabled() || chr.getPyramidSubway() != null) { //no drops in pyramid ok? no cash either return; } //We choose not to readLock for this. //This will not affect the internal state, and we don't want to //introduce unneccessary locking, especially since this function //is probably used quite often. if (!instanced && mapobjects.get(MapleMapObjectType.ITEM).size() >= 250) { removeDrops(); } final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); final byte droptype = (byte) (mob.getStats().isExplosiveReward() ? 3 : mob.getStats().isFfaLoot() ? 2 : chr.getParty() != null ? 1 : 0); final int mobpos = mob.getTruePosition().x, cmServerrate = ChannelServer.getInstance(channel).getMesoRate(), chServerrate = ChannelServer.getInstance(channel).getDropRate(), caServerrate = ChannelServer.getInstance(channel).getCashRate(); Item idrop; byte d = 1; Point pos = new Point(0, mob.getTruePosition().y); double showdown = 100.0; final MonsterStatusEffect mse = mob.getBuff(MonsterStatus.SHOWDOWN); if (mse != null) { showdown += mse.getX(); } final MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance(); final List<MonsterDropEntry> derp = mi.retrieveDrop(mob.getId()); if (derp == null) { //if no drops, no global drops either <3 return; } final List<MonsterDropEntry> dropEntry = new ArrayList<>(derp); Collections.shuffle(dropEntry); boolean mesoDropped = false; for (final MonsterDropEntry de : dropEntry) { if (de.itemId == mob.getStolen()) { continue; } if (Randomizer.nextInt(999999) < (int) (de.chance * chServerrate * chr.getDropMod() * (chr.getStat().dropBuff / 100.0) * (showdown / 100.0))) { if (mesoDropped && droptype != 3 && de.itemId == 0) { //not more than 1 sack of meso continue; } if (de.questid > 0 && chr.getQuestStatus(de.questid) != 1) { continue; } if (de.itemId / 10000 == 238 && !mob.getStats().isBoss() && chr.getMonsterBook().getLevelByCard(ii.getCardMobId(de.itemId)) >= 2) { continue; } if (droptype == 3) { pos.x = (mobpos + (d % 2 == 0 ? (40 * (d + 1) / 2) : -(40 * (d / 2)))); } else { pos.x = (mobpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2)))); } if (de.itemId == 0) { // meso int mesos = Randomizer.nextInt(1 + Math.abs(de.Maximum - de.Minimum)) + de.Minimum; if (mesos > 0) { spawnMobMesoDrop((int) (mesos * (chr.getStat().mesoBuff / 100.0) * chr.getDropMod() * cmServerrate), calcDropPos(pos, mob.getTruePosition()), mob, chr, false, droptype); mesoDropped = true; } } else { if (GameConstants.getInventoryType(de.itemId) == MapleInventoryType.EQUIP) { idrop = ii.randomizeStats((Equip) ii.getEquipById(de.itemId)); } else { final int range = Math.abs(de.Maximum - de.Minimum); idrop = new Item(de.itemId, (byte) 0, (short) (de.Maximum != 1 ? Randomizer.nextInt(range <= 0 ? 1 : range) + de.Minimum : 1), (byte) 0); } idrop.setGMLog("Dropped from monster " + mob.getId() + " on " + mapid); spawnMobDrop(idrop, calcDropPos(pos, mob.getTruePosition()), mob, chr, droptype, de.questid); } d++; } } final List<MonsterGlobalDropEntry> globalEntry = new ArrayList<>(mi.getGlobalDrop()); Collections.shuffle(globalEntry); // final int cashz = (int) ((mob.getStats().isBoss() && mob.getStats().getHPDisplayType() == 0 ? 20 : 1) * caServerrate); // final int cashModifier = (int) ((mob.getStats().isBoss() ? (mob.getStats().isPartyBonus() ? (mob.getMobExp() / 1000) : 0) : (mob.getMobExp() / 1000 + mob.getMobMaxHp() / 20000))); //no rate // Global Drops for (final MonsterGlobalDropEntry de : globalEntry) { if (Randomizer.nextInt(999999) < de.chance && (de.continent < 0 || (de.continent < 10 && mapid / 100000000 == de.continent) || (de.continent < 100 && mapid / 10000000 == de.continent) || (de.continent < 1000 && mapid / 1000000 == de.continent))) { if (de.questid > 0 && chr.getQuestStatus(de.questid) != 1) { continue; } if (de.itemId == 0) { chr.modifyCSPoints(1, 10, true); } else if (!gDropsDisabled) { if (droptype == 3) { pos.x = (mobpos + (d % 2 == 0 ? (40 * (d + 1) / 2) : -(40 * (d / 2)))); } else { pos.x = (mobpos + ((d % 2 == 0) ? (25 * (d + 1) / 2) : -(25 * (d / 2)))); } if (GameConstants.getInventoryType(de.itemId) == MapleInventoryType.EQUIP) { idrop = ii.randomizeStats((Equip) ii.getEquipById(de.itemId)); } else { idrop = new Item(de.itemId, (byte) 0, (short) (de.Maximum != 1 ? Randomizer.nextInt(de.Maximum - de.Minimum) + de.Minimum : 1), (byte) 0); } idrop.setGMLog("Dropped from monster " + mob.getId() + " on " + mapid + " (Global)"); spawnMobDrop(idrop, calcDropPos(pos, mob.getTruePosition()), mob, chr, de.onlySelf ? 0 : droptype, de.questid); d++; } } } } public void removeMonster(MapleMonster monster) { if (monster == null) { return; } this.spawnedMonstersOnMap.decrementAndGet(); broadcastMessage(MobPacket.killMonster(monster.getObjectId(), 0)); removeMapObject(monster); monster.killed(); } public void killMonster(final MapleMonster monster) { // For mobs with removeAfter if (monster == null) { return; } spawnedMonstersOnMap.decrementAndGet(); monster.setHp(0); if (monster.getLinkCID() <= 0) { monster.spawnRevives(this); } broadcastMessage(MobPacket.killMonster(monster.getObjectId(), monster.getStats().getSelfD() < 0 ? 1 : monster.getStats().getSelfD())); removeMapObject(monster); monster.killed(); } public final void killMonster(MapleMonster monster, MapleCharacter chr, boolean withDrops, boolean second, byte animation) { killMonster(monster, chr, withDrops, second, animation, 0); } public final void killMonster(final MapleMonster monster, final MapleCharacter chr, boolean withDrops, boolean second, byte animation, int lastSkill) { if (((monster.getId() == 8810122) || (monster.getId() == 8810018)) && (!second)) { Timer.MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { MapleMap.this.killMonster(monster, chr, true, true, (byte) 1); MapleMap.this.killAllMonsters(true); } }, 3000L); return; } if (monster.getId() == 8820014) { killMonster(8820000); } else if (monster.getId() == 9300166) { animation = 4; } this.spawnedMonstersOnMap.decrementAndGet(); removeMapObject(monster); monster.killed(); MapleSquad sqd = getSquadByMap(); boolean instanced = (sqd != null) || (monster.getEventInstance() != null) || (getEMByMap() != null); int dropOwner = monster.killBy(chr, lastSkill); if (animation >= 0) { broadcastMessage(MobPacket.killMonster(monster.getObjectId(), animation)); } if (monster.getBuffToGive() > -1) { int buffid = monster.getBuffToGive(); MapleStatEffect buff = MapleItemInformationProvider.getInstance().getItemEffect(buffid); this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { if (mc.isAlive()) { buff.applyTo(mc); switch (monster.getId()) { case 8810018: case 8810122: case 8820001: mc.getClient().getSession().write(CField.EffectPacket.showOwnBuffEffect(buffid, 13, mc.getLevel(), 1)); broadcastMessage(mc, CField.EffectPacket.showBuffeffect(mc.getId(), buffid, 13, mc.getLevel(), 1), false); } } } } finally { this.charactersLock.readLock().unlock(); } } int mobid = monster.getId(); ExpeditionType type = null; if ((mobid == 8810018) && (this.mapid == 240060200)) { charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { //c.finishAchievement(16); } } finally { charactersLock.readLock().unlock(); } //FileoutputUtil.log(FileoutputUtil.Horntail_Log, MapDebug_Log()); if (speedRunStart > 0) { type = ExpeditionType.Horntail; } doShrine(true); } else if ((mobid == 8810122) && (this.mapid == 240060201)) { World.Broadcast.broadcastMessage(CWvsContext.serverNotice(6, "To the crew that have finally conquered Chaos Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!")); charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { /// c.finishAchievement(24); } } finally { charactersLock.readLock().unlock(); } // FileoutputUtil.log(FileoutputUtil.Horntail_Log, MapDebug_Log()); if (speedRunStart > 0) { type = ExpeditionType.ChaosHT; } doShrine(true); } else if ((mobid == 9400266) && (this.mapid == 802000111)) { doShrine(true); } else if ((mobid == 9400265) && (this.mapid == 802000211)) { doShrine(true); } else if ((mobid == 9400270) && (this.mapid == 802000411)) { doShrine(true); } else if ((mobid == 9400273) && (this.mapid == 802000611)) { doShrine(true); } else if ((mobid == 9400294) && (this.mapid == 802000711)) { doShrine(true); } else if ((mobid == 9400296) && (this.mapid == 802000803)) { doShrine(true); } else if ((mobid == 9400289) && (this.mapid == 802000821)) { doShrine(true); } else if ((getAllMonstersThreadsafe().isEmpty()) && (this.mapid == 955000100)) { if (getPlayer() != null) { getPlayer().broadcastPacket(CField.showEffect("aswan/clear")); getPlayer().dropMessage(6, "[Hilla's Gang Liberation] Portal to continue has been unblocked!"); } } else if ((getAllMonstersThreadsafe().isEmpty()) && (this.mapid == 955000200)) { if (getPlayer() != null) { getPlayer().broadcastPacket(CField.showEffect("aswan/clear")); getPlayer().dropMessage(6, "[Hilla's Gang Liberation] Portal to continue has been unblocked!"); } } else if ((getAllMonstersThreadsafe().isEmpty()) && (this.mapid == 955000300)) { if (getPlayer() != null) { getPlayer().broadcastPacket(CField.showEffect("aswan/clear")); getPlayer().dropMessage(6, "[Hilla's Gang Liberation] Enter the portal to claim your reward!"); } } else if ((mobid == 8830000) && (this.mapid == 105100300)) { if (this.speedRunStart > 0L) { type = ExpeditionType.Normal_Balrog; } } else if (((mobid == 9420544) || (mobid == 9420549)) && (this.mapid == 551030200) && (monster.getEventInstance() != null) && (monster.getEventInstance().getName().contains(getEMByMap().getName()))) { doShrine(getAllReactor().isEmpty()); } else if ((mobid == 8820001) && (this.mapid == 270050100)) { World.Broadcast.broadcastMessage(CWvsContext.serverNotice(6, "Oh, the exploration team who has defeated Pink Bean with undying fervor! You are the true victors of time!")); charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { // c.finishAchievement(17); } } finally { charactersLock.readLock().unlock(); } if (speedRunStart > 0) { type = ExpeditionType.Pink_Bean; } doShrine(true); } else if ((mobid == 8850011) && (this.mapid == 274040200)) { World.Broadcast.broadcastMessage(CWvsContext.serverNotice(6, "To you whom have defeated Empress Cygnus in the future, you are the heroes of time!")); charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { // c.finishAchievement(39); } } finally { charactersLock.readLock().unlock(); } if (speedRunStart > 0) { type = ExpeditionType.Cygnus; } doShrine(true); } else if ((mobid == 8870000) && (this.mapid == 262031300)) { this.charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { // c.finishAchievement(39); } } finally { MapleCharacter c; this.charactersLock.readLock().unlock(); } if (this.speedRunStart > 0L) { type = ExpeditionType.Hilla; } doShrine(true); } else if ((mobid == 8840000) && (this.mapid == 211070100)) { this.charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { // c.finishAchievement(39); } } finally { MapleCharacter c; this.charactersLock.readLock().unlock(); } if (this.speedRunStart > 0L) { type = ExpeditionType.Von_Leon; } doShrine(true); } else if ((mobid == 8800002) && (this.mapid == 280030000)) { this.charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { // c.finishAchievement(39); } } finally { MapleCharacter c; this.charactersLock.readLock().unlock(); } if (this.speedRunStart > 0L) { type = ExpeditionType.Zakum; } doShrine(true); } else if ((mobid == 8800102) && (this.mapid == 280030001)) { this.charactersLock.readLock().lock(); try { for (MapleCharacter c : characters) { // c.finishAchievement(39); } } finally { MapleCharacter c; this.charactersLock.readLock().unlock(); } if (this.speedRunStart > 0L) { type = ExpeditionType.Chaos_Zakum; } doShrine(true); } else if ((mobid >= 8800003) && (mobid <= 8800010)) { boolean makeZakReal = true; List<MapleMonster> monsters = getAllMonstersThreadsafe(); for (MapleMonster mons : monsters) { if ((mons.getId() >= 8800003) && (mons.getId() <= 8800010)) { makeZakReal = false; break; } } if (makeZakReal) { for (MapleMapObject object : monsters) { MapleMonster mons = (MapleMonster) object; if (mons.getId() == 8800000) { Point pos = mons.getTruePosition(); killAllMonsters(true); spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8800000), pos); break; } } } } else if ((mobid >= 8800103) && (mobid <= 8800110)) { boolean makeZakReal = true; List<MapleMonster> monsters = getAllMonstersThreadsafe(); for (MapleMonster mons : monsters) { if ((mons.getId() >= 8800103) && (mons.getId() <= 8800110)) { makeZakReal = false; break; } } if (makeZakReal) { for (MapleMonster mons : monsters) { if (mons.getId() == 8800100) { Point pos = mons.getTruePosition(); killAllMonsters(true); spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8800100), pos); break; } } } } else if (mobid == 8820008) { for (MapleMapObject mmo : getAllMonstersThreadsafe()) { MapleMonster mons = (MapleMonster) mmo; if (mons.getLinkOid() != monster.getObjectId()) { killMonster(mons, chr, false, false, animation); } } } else if ((mobid >= 8820010) && (mobid <= 8820014)) { for (MapleMapObject mmo : getAllMonstersThreadsafe()) { MapleMonster mons = (MapleMonster) mmo; if ((mons.getId() != 8820000) && (mons.getId() != 8820001) && (mons.getObjectId() != monster.getObjectId()) && (mons.isAlive()) && (mons.getLinkOid() == monster.getObjectId())) { killMonster(mons, chr, false, false, animation); } } } else if ((mobid / 100000 == 98) && (chr.getMapId() / 10000000 == 95) && (getAllMonstersThreadsafe().size() == 0)) { switch (chr.getMapId() % 1000 / 100) { case 0: case 1: case 2: case 3: case 4: chr.getClient().getSession().write(CField.MapEff("monsterPark/clear")); break; case 5: if (chr.getMapId() / 1000000 == 952) { chr.getClient().getSession().write(CField.MapEff("monsterPark/clearF")); } else { chr.getClient().getSession().write(CField.MapEff("monsterPark/clear")); } break; case 6: chr.getClient().getSession().write(CField.MapEff("monsterPark/clearF")); } } if ((type != null) && (this.speedRunStart > 0L) && (this.speedRunLeader.length() > 0)) { long endTime = System.currentTimeMillis(); String time = StringUtil.getReadableMillis(this.speedRunStart, endTime); broadcastMessage(CWvsContext.serverNotice(5, new StringBuilder().append(this.speedRunLeader).append("'s squad has taken ").append(time).append(" to defeat ").append(type.name()).append("!").toString())); getRankAndAdd(this.speedRunLeader, time, type, endTime - this.speedRunStart, sqd == null ? null : sqd.getMembers()); endSpeedRun(); } if (withDrops) { MapleCharacter drop = null; if (dropOwner <= 0) { drop = chr; } else { drop = getCharacterById(dropOwner); if (drop == null) { drop = chr; } } dropFromMonster(drop, monster, instanced); } } public List<MapleReactor> getAllReactor() { return getAllReactorsThreadsafe(); } public List<MapleReactor> getAllReactorsThreadsafe() { ArrayList<MapleReactor> ret = new ArrayList<MapleReactor>(); mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.REACTOR).values()) { ret.add((MapleReactor) mmo); } } finally { mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().unlock(); } return ret; } public List<MapleSummon> getAllSummonsThreadsafe() { ArrayList<MapleSummon> ret = new ArrayList<MapleSummon>(); mapobjectlocks.get(MapleMapObjectType.SUMMON).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.SUMMON).values()) { if (mmo instanceof MapleSummon) { ret.add((MapleSummon) mmo); } } } finally { mapobjectlocks.get(MapleMapObjectType.SUMMON).readLock().unlock(); } return ret; } public List<MapleMapObject> getAllDoor() { return getAllDoorsThreadsafe(); } public List<MapleMapObject> getAllDoorsThreadsafe() { ArrayList<MapleMapObject> ret = new ArrayList<MapleMapObject>(); mapobjectlocks.get(MapleMapObjectType.DOOR).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.DOOR).values()) { if (mmo instanceof MapleDoor) { ret.add(mmo); } } } finally { mapobjectlocks.get(MapleMapObjectType.DOOR).readLock().unlock(); } return ret; } public List<MapleMapObject> getAllMechDoorsThreadsafe() { ArrayList<MapleMapObject> ret = new ArrayList<MapleMapObject>(); mapobjectlocks.get(MapleMapObjectType.DOOR).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.DOOR).values()) { if (mmo instanceof MechDoor) { ret.add(mmo); } } } finally { mapobjectlocks.get(MapleMapObjectType.DOOR).readLock().unlock(); } return ret; } public List<MapleMapObject> getAllMerchant() { return getAllHiredMerchantsThreadsafe(); } public List<MapleMapObject> getAllHiredMerchantsThreadsafe() { ArrayList<MapleMapObject> ret = new ArrayList<MapleMapObject>(); mapobjectlocks.get(MapleMapObjectType.HIRED_MERCHANT).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.HIRED_MERCHANT).values()) { ret.add(mmo); } } finally { mapobjectlocks.get(MapleMapObjectType.HIRED_MERCHANT).readLock().unlock(); } return ret; } public List<MapleMonster> getAllMonster() { return getAllMonstersThreadsafe(); } public List<MapleMonster> getAllMonstersThreadsafe() { ArrayList<MapleMonster> ret = new ArrayList<MapleMonster>(); mapobjectlocks.get(MapleMapObjectType.MONSTER).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.MONSTER).values()) { ret.add((MapleMonster) mmo); } } finally { mapobjectlocks.get(MapleMapObjectType.MONSTER).readLock().unlock(); } return ret; } public List<Integer> getAllUniqueMonsters() { ArrayList<Integer> ret = new ArrayList<Integer>(); mapobjectlocks.get(MapleMapObjectType.MONSTER).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.MONSTER).values()) { final int theId = ((MapleMonster) mmo).getId(); if (!ret.contains(theId)) { ret.add(theId); } } } finally { mapobjectlocks.get(MapleMapObjectType.MONSTER).readLock().unlock(); } return ret; } public final void killAllMonsters(boolean animate) { for (MapleMapObject monstermo : getAllMonstersThreadsafe()) { MapleMonster monster = (MapleMonster) monstermo; this.spawnedMonstersOnMap.decrementAndGet(); monster.setHp(0L); broadcastMessage(MobPacket.killMonster(monster.getObjectId(), animate ? 1 : 0)); removeMapObject(monster); monster.killed(); } } public final void killMonster(int monsId) { for (MapleMapObject mmo : getAllMonstersThreadsafe()) { if (((MapleMonster) mmo).getId() == monsId) { this.spawnedMonstersOnMap.decrementAndGet(); removeMapObject(mmo); broadcastMessage(MobPacket.killMonster(mmo.getObjectId(), 1)); ((MapleMonster) mmo).killed(); break; } } } private String MapDebug_Log() { StringBuilder sb = new StringBuilder("Defeat time : "); sb.append(FileoutputUtil.CurrentReadable_Time()); sb.append(" | Mapid : ").append(this.mapid); this.charactersLock.readLock().lock(); try { sb.append(" Users [").append(this.characters.size()).append("] | "); for (MapleCharacter mc : this.characters) { sb.append(mc.getName()).append(", "); } } finally { this.charactersLock.readLock().unlock(); } return sb.toString(); } public final void limitReactor(int rid, int num) { List<MapleReactor> toDestroy = new ArrayList(); Map<Integer, Integer> contained = new LinkedHashMap(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor mr = (MapleReactor) obj; if (contained.containsKey(Integer.valueOf(mr.getReactorId()))) { if (((Integer) contained.get(Integer.valueOf(mr.getReactorId()))).intValue() >= num) { toDestroy.add(mr); } else { contained.put(Integer.valueOf(mr.getReactorId()), Integer.valueOf(((Integer) contained.get(Integer.valueOf(mr.getReactorId()))).intValue() + 1)); } } else { contained.put(Integer.valueOf(mr.getReactorId()), Integer.valueOf(1)); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } for (MapleReactor mr : toDestroy) { destroyReactor(mr.getObjectId()); } } public final void destroyReactors(int first, int last) { List<MapleReactor> toDestroy = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor mr = (MapleReactor) obj; if ((mr.getReactorId() >= first) && (mr.getReactorId() <= last)) { toDestroy.add(mr); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } for (MapleReactor mr : toDestroy) { destroyReactor(mr.getObjectId()); } } public final void destroyReactor(int oid) { final MapleReactor reactor = getReactorByOid(oid); if (reactor == null) { return; } broadcastMessage(CField.destroyReactor(reactor)); reactor.setAlive(false); removeMapObject(reactor); reactor.setTimerActive(false); if (reactor.getDelay() > 0) { Timer.MapTimer.getInstance().schedule(new Runnable() { public final void run() { MapleMap.this.respawnReactor(reactor); } }, reactor.getDelay()); } } public final void reloadReactors() { List<MapleReactor> toSpawn = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor reactor = (MapleReactor) obj; broadcastMessage(CField.destroyReactor(reactor)); reactor.setAlive(false); reactor.setTimerActive(false); toSpawn.add(reactor); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } for (MapleReactor r : toSpawn) { removeMapObject(r); if (!r.isCustom()) { respawnReactor(r); } } } public final void resetReactors() { setReactorState((byte) 0); } public final void setReactorState() { setReactorState((byte) 1); } public final void setReactorState(final byte state) { mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { ((MapleReactor) obj).forceHitReactor((byte) state); } } finally { mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().unlock(); } } public final void setReactorDelay(final int state) { mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { ((MapleReactor) obj).setDelay(state); } } finally { mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().unlock(); } } public final void shuffleReactors() { shuffleReactors(0, 9999999); } public final void shuffleReactors(int first, int last) { List points = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor mr = (MapleReactor) obj; if ((mr.getReactorId() >= first) && (mr.getReactorId() <= last)) { points.add(mr.getPosition()); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } Collections.shuffle(points); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor mr = (MapleReactor) obj; if ((mr.getReactorId() >= first) && (mr.getReactorId() <= last)) { mr.setPosition((Point) points.remove(points.size() - 1)); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } } public final void updateMonsterController(MapleMonster monster) { if ((!monster.isAlive()) || (monster.getLinkCID() > 0) || (monster.getStats().isEscort())) { return; } if (monster.getController() != null) { if ((monster.getController().getMap() != this) || (monster.getController().getTruePosition().distanceSq(monster.getTruePosition()) > monster.getRange())) { monster.getController().stopControllingMonster(monster); } else { return; } } int mincontrolled = -1; MapleCharacter newController = null; this.charactersLock.readLock().lock(); try { Iterator ltr = this.characters.iterator(); while (ltr.hasNext()) { MapleCharacter chr = (MapleCharacter) ltr.next(); if ((!chr.isHidden()) && (!chr.isClone()) && ((chr.getControlledSize() < mincontrolled) || (mincontrolled == -1)) && (chr.getTruePosition().distanceSq(monster.getTruePosition()) <= monster.getRange())) { mincontrolled = chr.getControlledSize(); newController = chr; } } } finally { this.charactersLock.readLock().unlock(); } if (newController != null) { if (monster.isFirstAttack()) { newController.controlMonster(monster, true); monster.setControllerHasAggro(true); } else { newController.controlMonster(monster, false); } } } public final MapleMapObject getMapObject(int oid, MapleMapObjectType type) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().lock(); try { return (MapleMapObject) ((LinkedHashMap) this.mapobjects.get(type)).get(Integer.valueOf(oid)); } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().unlock(); } } public final boolean containsNPC(int npcid) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.NPC)).values().iterator(); MapleNPC n; while (itr.hasNext()) { n = (MapleNPC) itr.next(); if (n.getId() == npcid) { return true; } } return false; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().unlock(); } } public MapleNPC getNPCById(int id) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.NPC)).values().iterator(); MapleNPC n; while (itr.hasNext()) { n = (MapleNPC) itr.next(); if (n.getId() == id) { return n; } } return null; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().unlock(); } } public MapleMonster getMonsterById(int id) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().lock(); try { MapleMonster ret = null; Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.MONSTER)).values().iterator(); MapleMonster n; while (itr.hasNext()) { n = (MapleMonster) itr.next(); if (n.getId() == id) { ret = n; break; } } return ret; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().unlock(); } } public int countMonsterById(int id) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().lock(); try { int ret = 0; Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.MONSTER)).values().iterator(); MapleMonster n; while (itr.hasNext()) { n = (MapleMonster) itr.next(); if (n.getId() == id) { ret++; } } return ret; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().unlock(); } } public MapleReactor getReactorById(int id) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { MapleReactor ret = null; Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.REACTOR)).values().iterator(); MapleReactor n; while (itr.hasNext()) { n = (MapleReactor) itr.next(); if (n.getReactorId() == id) { ret = n; break; } } return ret; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } } public final MapleMonster getMonsterByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.MONSTER); if (mmo == null) { return null; } return (MapleMonster) mmo; } public final MapleNPC getNPCByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.NPC); if (mmo == null) { return null; } return (MapleNPC) mmo; } public final MapleReactor getReactorByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.REACTOR); if (mmo == null) { return null; } return (MapleReactor) mmo; } public final MonsterFamiliar getFamiliarByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.FAMILIAR); if (mmo == null) { return null; } return (MonsterFamiliar) mmo; } public final MapleReactor getReactorByName(String name) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor mr = (MapleReactor) obj; if (mr.getName().equalsIgnoreCase(name)) { return mr; } } return null; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } } public final void spawnNpc(int id, Point pos) { MapleNPC npc = MapleLifeFactory.getNPC(id); npc.setPosition(pos); npc.setCy(pos.y); npc.setRx0(pos.x + 50); npc.setRx1(pos.x - 50); npc.setFh(getFootholds().findBelow(pos).getId()); npc.setCustom(true); addMapObject(npc); broadcastMessage(CField.NPCPacket.spawnNPC(npc, true)); } public final void removeNpc(int npcid) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).writeLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.NPC)).values().iterator(); while (itr.hasNext()) { MapleNPC npc = (MapleNPC) itr.next(); if ((npc.isCustom()) && ((npcid == -1) || (npc.getId() == npcid))) { broadcastMessage(CField.NPCPacket.removeNPCController(npc.getObjectId())); broadcastMessage(CField.NPCPacket.removeNPC(npc.getObjectId())); itr.remove(); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).writeLock().unlock(); } } public final void hideNpc(int npcid) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.NPC)).values().iterator(); while (itr.hasNext()) { MapleNPC npc = (MapleNPC) itr.next(); if ((npcid == -1) || (npc.getId() == npcid)) { broadcastMessage(CField.NPCPacket.removeNPCController(npc.getObjectId())); broadcastMessage(CField.NPCPacket.removeNPC(npc.getObjectId())); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().unlock(); } } public final void spawnReactorOnGroundBelow(MapleReactor mob, Point pos) { mob.setPosition(pos); mob.setCustom(true); spawnReactor(mob); } public final void spawnMonster_sSack(MapleMonster mob, Point pos, int spawnType) { mob.setPosition(calcPointBelow(new Point(pos.x, pos.y - 1))); spawnMonster(mob, spawnType); } public final void spawnMonsterOnGroundBelow(MapleMonster mob, Point pos) { spawnMonster_sSack(mob, pos, -2); } public final int spawnMonsterWithEffectBelow(MapleMonster mob, Point pos, int effect) { Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); return spawnMonsterWithEffect(mob, effect, spos); } public final void spawnZakum(int x, int y) { Point pos = new Point(x, y); MapleMonster mainb = MapleLifeFactory.getMonster(8800000); Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); mainb.setPosition(spos); mainb.setFake(true); spawnFakeMonster(mainb); int[] zakpart = {8800003, 8800004, 8800005, 8800006, 8800007, 8800008, 8800009, 8800010}; for (int i : zakpart) { MapleMonster part = MapleLifeFactory.getMonster(i); part.setPosition(spos); spawnMonster(part, -2); } if (this.squadSchedule != null) { cancelSquadSchedule(false); } } public final void spawnChaosZakum(int x, int y) { Point pos = new Point(x, y); MapleMonster mainb = MapleLifeFactory.getMonster(8800100); Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); mainb.setPosition(spos); mainb.setFake(true); spawnFakeMonster(mainb); int[] zakpart = {8800103, 8800104, 8800105, 8800106, 8800107, 8800108, 8800109, 8800110}; for (int i : zakpart) { MapleMonster part = MapleLifeFactory.getMonster(i); part.setPosition(spos); spawnMonster(part, -2); } if (this.squadSchedule != null) { cancelSquadSchedule(false); } } public final void spawnFakeMonsterOnGroundBelow(MapleMonster mob, Point pos) { Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); spos.y -= 1; mob.setPosition(spos); spawnFakeMonster(mob); } private void checkRemoveAfter(MapleMonster monster) { int ra = monster.getStats().getRemoveAfter(); if ((ra > 0) && (monster.getLinkCID() <= 0)) { monster.registerKill(ra * 1000); } } public final void spawnRevives(final MapleMonster monster, final int oid) { monster.setMap(this); checkRemoveAfter(monster); monster.setLinkOid(oid); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { c.getSession().write(MobPacket.spawnMonster(monster, monster.getStats().getSummonType() <= 1 ? -3 : monster.getStats().getSummonType(), oid)); } }); updateMonsterController(monster); this.spawnedMonstersOnMap.incrementAndGet(); } public final void spawnMonster(MapleMonster monster, int spawnType) { spawnMonster(monster, spawnType, false); } public final void spawnMonster(final MapleMonster monster, final int spawnType, final boolean overwrite) { //Channel check. if (channel == 21) { //List of bosses to transform. Bosses only get x36 HP, rather than x200. for (int m : GameConstants.mobBuff) { if (monster.getId() == m) { //In order: (newLevel, hpMulti, bossHpMulti, expMulti) monster.hellChangeLevel(monster.getStats().getLevel() * 1.5, 320, 36, 16); break; } else { monster.hellChangeLevel(monster.getStats().getLevel() * 1.5, 320, 200, 16); } } } monster.setMap(this); checkRemoveAfter(monster); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { c.getSession().write(MobPacket.spawnMonster(monster, (monster.getStats().getSummonType() <= 1) || (monster.getStats().getSummonType() == 27) || (overwrite) ? spawnType : monster.getStats().getSummonType(), 0)); } }); updateMonsterController(monster); this.spawnedMonstersOnMap.incrementAndGet(); } public final int spawnMonsterWithEffect(final MapleMonster monster, final int effect, Point pos) { try { monster.setMap(this); monster.setPosition(pos); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { c.getSession().write(MobPacket.spawnMonster(monster, effect, 0)); } }); updateMonsterController(monster); this.spawnedMonstersOnMap.incrementAndGet(); return monster.getObjectId(); } catch (Exception e) { } return -1; } public final void spawnFakeMonster(final MapleMonster monster) { monster.setMap(this); monster.setFake(true); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { c.getSession().write(MobPacket.spawnMonster(monster, -4, 0)); } }); updateMonsterController(monster); this.spawnedMonstersOnMap.incrementAndGet(); } public final void spawnReactor(final MapleReactor reactor) { reactor.setMap(this); spawnAndAddRangedMapObject(reactor, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { c.getSession().write(CField.spawnReactor(reactor)); } }); } private void respawnReactor(MapleReactor reactor) { reactor.setState((byte) 0); reactor.setAlive(true); spawnReactor(reactor); } public final void spawnDoor(final MapleDoor door) { spawnAndAddRangedMapObject(door, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { door.sendSpawnData(c); c.getSession().write(CWvsContext.enableActions()); } }); } public final void spawnMechDoor(final MechDoor door) { spawnAndAddRangedMapObject(door, new DelayedPacketCreation() { @Override public final void sendPackets(MapleClient c) { c.getSession().write(CField.spawnMechDoor(door, true)); c.getSession().write(CWvsContext.enableActions()); } }); } public final void spawnSummon(final MapleSummon summon) { summon.updateMap(this); spawnAndAddRangedMapObject(summon, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { if ((summon != null) && (c.getPlayer() != null) && ((!summon.isChangedMap()) || (summon.getOwnerId() == c.getPlayer().getId()))) { c.getSession().write(CField.SummonPacket.spawnSummon(summon, true)); } } }); } public final void spawnFamiliar(final MonsterFamiliar familiar, final boolean respawn) { spawnAndAddRangedMapObject(familiar, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { if ((familiar != null) && (c.getPlayer() != null)) { c.getSession().write(CField.spawnFamiliar(familiar, true, respawn)); } } }); } public final void spawnExtractor(final MapleExtractor ex) { spawnAndAddRangedMapObject(ex, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { ex.sendSpawnData(c); } }); } public final void spawnMist(final MapleMist mist, final int duration, boolean fake) { spawnAndAddRangedMapObject(mist, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { mist.sendSpawnData(c); } }); Timer.MapTimer tMan = Timer.MapTimer.getInstance(); final ScheduledFuture poisonSchedule; switch (mist.isPoisonMist()) { case 1: final MapleCharacter owner = getCharacterById(mist.getOwnerId()); final boolean pvp = owner.inPVP(); poisonSchedule = tMan.register(new Runnable() { public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList(pvp ? MapleMapObjectType.PLAYER : MapleMapObjectType.MONSTER))) { if ((pvp) && (mist.makeChanceResult()) && (!((MapleCharacter) mo).hasDOT()) && (((MapleCharacter) mo).getId() != mist.getOwnerId())) { ((MapleCharacter) mo).setDOT(mist.getSource().getDOT(), mist.getSourceSkill().getId(), mist.getSkillLevel()); } else if ((!pvp) && (mist.makeChanceResult()) && (!((MapleMonster) mo).isBuffed(MonsterStatus.POISON))) { ((MapleMonster) mo).applyStatus(owner, new MonsterStatusEffect(MonsterStatus.POISON, Integer.valueOf(1), mist.getSourceSkill().getId(), null, false), true, duration, true, mist.getSource()); } } } }, 2000L, 2500L); break; case 4: poisonSchedule = tMan.register(new Runnable() { public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList(MapleMapObjectType.PLAYER))) { if (mist.makeChanceResult()) { MapleCharacter chr = (MapleCharacter) mo; chr.addMP((int) (mist.getSource().getX() * (chr.getStat().getMaxMp() / 100.0D))); } } } }, 2000L, 2500L); break; default: poisonSchedule = null; } mist.setPoisonSchedule(poisonSchedule); mist.setSchedule(tMan.schedule(new Runnable() { public void run() { MapleMap.this.broadcastMessage(CField.removeMist(mist.getObjectId(), false)); MapleMap.this.removeMapObject(mist); if (poisonSchedule != null) { poisonSchedule.cancel(false); } } }, duration)); } public final void disappearingItemDrop(MapleMapObject dropper, MapleCharacter owner, Item item, Point pos) { Point droppos = calcDropPos(pos, pos); MapleMapItem drop = new MapleMapItem(item, droppos, dropper, owner, (byte) 1, false); broadcastMessage(CField.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 3), drop.getTruePosition()); } public final void spawnMesoDrop(int meso, Point position, final MapleMapObject dropper, MapleCharacter owner, boolean playerDrop, byte droptype) { final Point droppos = calcDropPos(position, position); final MapleMapItem mdrop = new MapleMapItem(meso, droppos, dropper, owner, droptype, playerDrop); spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() { public void sendPackets(MapleClient c) { c.getSession().write(CField.dropItemFromMapObject(mdrop, dropper.getTruePosition(), droppos, (byte) 1)); } }); if (!this.everlast) { mdrop.registerExpire(120000L); if ((droptype == 0) || (droptype == 1)) { mdrop.registerFFA(30000L); } } } public final void spawnMobMesoDrop(int meso, final Point position, final MapleMapObject dropper, MapleCharacter owner, boolean playerDrop, byte droptype) { final MapleMapItem mdrop = new MapleMapItem(meso, position, dropper, owner, droptype, playerDrop); spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() { public void sendPackets(MapleClient c) { c.getSession().write(CField.dropItemFromMapObject(mdrop, dropper.getTruePosition(), position, (byte) 1)); } }); mdrop.registerExpire(120000L); if ((droptype == 0) || (droptype == 1)) { mdrop.registerFFA(30000L); } } public final void spawnMobDrop(final Item idrop, final Point dropPos, final MapleMonster mob, MapleCharacter chr, byte droptype, final int questid) { final MapleMapItem mdrop = new MapleMapItem(idrop, dropPos, mob, chr, droptype, false, questid); spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() { public void sendPackets(MapleClient c) { if ((c != null) && (c.getPlayer() != null) && ((questid <= 0) || (c.getPlayer().getQuestStatus(questid) == 1)) && ((idrop.getItemId() / 10000 != 238) || (c.getPlayer().getMonsterBook().getLevelByCard(idrop.getItemId()) >= 2)) && (mob != null) && (dropPos != null)) { c.getSession().write(CField.dropItemFromMapObject(mdrop, mob.getTruePosition(), dropPos, (byte) 1)); } } }); mdrop.registerExpire(120000L); if ((droptype == 0) || (droptype == 1)) { mdrop.registerFFA(30000L); } activateItemReactors(mdrop, chr.getClient()); } public final void spawnRandDrop() { if (mapid != 910000000 || channel != 1) { return; //fm, ch1 } mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().lock(); try { for (MapleMapObject o : mapobjects.get(MapleMapObjectType.ITEM).values()) { if (((MapleMapItem) o).isRandDrop()) { return; } } } finally { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().unlock(); } MapTimer.getInstance().schedule(new Runnable() { public void run() { final Point pos = new Point(Randomizer.nextInt(800) + 531, -806); final int theItem = Randomizer.nextInt(1000); int itemid = 0; if (theItem < 950) { //0-949 = normal, 950-989 = rare, 990-999 = super itemid = GameConstants.normalDrops[Randomizer.nextInt(GameConstants.normalDrops.length)]; } else if (theItem < 990) { itemid = GameConstants.rareDrops[Randomizer.nextInt(GameConstants.rareDrops.length)]; } else { itemid = GameConstants.superDrops[Randomizer.nextInt(GameConstants.superDrops.length)]; } spawnAutoDrop(itemid, pos); } }, 20000); } public final void spawnAutoDrop(final int itemid, final Point pos) { Item idrop = null; final MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); if (GameConstants.getInventoryType(itemid) == MapleInventoryType.EQUIP) { idrop = ii.randomizeStats((Equip) ii.getEquipById(itemid)); } else { idrop = new Item(itemid, (byte) 0, (short) 1, (byte) 0); } idrop.setGMLog("Dropped from auto " + " on " + mapid); final MapleMapItem mdrop = new MapleMapItem(pos, idrop); spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { c.getSession().write(CField.dropItemFromMapObject(mdrop, pos, pos, (byte) 1)); } }); broadcastMessage(CField.dropItemFromMapObject(mdrop, pos, pos, (byte) 0)); if (itemid / 10000 != 291) { mdrop.registerExpire(120000); } } public final void spawnItemDrop(final MapleMapObject dropper, MapleCharacter owner, Item item, Point pos, boolean ffaDrop, boolean playerDrop) { final Point droppos = calcDropPos(pos, pos); final MapleMapItem drop = new MapleMapItem(item, droppos, dropper, owner, (byte) 2, playerDrop); spawnAndAddRangedMapObject(drop, new DelayedPacketCreation() { public void sendPackets(MapleClient c) { c.getSession().write(CField.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 1)); } }); broadcastMessage(CField.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 0)); if (!this.everlast) { drop.registerExpire(120000L); activateItemReactors(drop, owner.getClient()); } } private void activateItemReactors(final MapleMapItem drop, final MapleClient c) { final Item item = drop.getItem(); mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().lock(); try { for (final MapleMapObject o : mapobjects.get(MapleMapObjectType.REACTOR).values()) { final MapleReactor react = (MapleReactor) o; if (react.getReactorType() == 100) { if (item.getItemId() == GameConstants.getCustomReactItem(react.getReactorId(), react.getReactItem().getLeft()) && react.getReactItem().getRight() == item.getQuantity()) { if (react.getArea().contains(drop.getTruePosition())) { if (!react.isTimerActive()) { MapTimer.getInstance().schedule(new ActivateItemReactor(drop, react, c), 5000); react.setTimerActive(true); break; } } } } } } finally { mapobjectlocks.get(MapleMapObjectType.REACTOR).readLock().unlock(); } } public int getItemsSize() { return ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.ITEM)).size(); } public int getExtractorSize() { return ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.EXTRACTOR)).size(); } public int getMobsSize() { return ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.MONSTER)).size(); } public List<MapleMapItem> getAllItems() { return getAllItemsThreadsafe(); } public List<MapleMapItem> getAllItemsThreadsafe() { ArrayList<MapleMapItem> ret = new ArrayList<MapleMapItem>(); mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.ITEM).values()) { ret.add((MapleMapItem) mmo); } } finally { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().unlock(); } return ret; } public Point getPointOfItem(int itemid) { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.ITEM).values()) { MapleMapItem mm = ((MapleMapItem) mmo); if (mm.getItem() != null && mm.getItem().getItemId() == itemid) { return mm.getPosition(); } } } finally { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().unlock(); } return null; } public List<MapleMist> getAllMistsThreadsafe() { ArrayList<MapleMist> ret = new ArrayList<MapleMist>(); mapobjectlocks.get(MapleMapObjectType.MIST).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.MIST).values()) { ret.add((MapleMist) mmo); } } finally { mapobjectlocks.get(MapleMapObjectType.MIST).readLock().unlock(); } return ret; } public final void returnEverLastItem(final MapleCharacter chr) { for (final MapleMapObject o : getAllItemsThreadsafe()) { final MapleMapItem item = ((MapleMapItem) o); if (item.getOwner() == chr.getId()) { item.setPickedUp(true); broadcastMessage(CField.removeItemFromMap(item.getObjectId(), 2, chr.getId()), item.getTruePosition()); if (item.getMeso() > 0) { chr.gainMeso(item.getMeso(), false); } else { MapleInventoryManipulator.addFromDrop(chr.getClient(), item.getItem(), false); } removeMapObject(item); } } spawnRandDrop(); } public final void talkMonster(String msg, int itemId, int objectid) { if (itemId > 0) { startMapEffect(msg, itemId, false); } broadcastMessage(MobPacket.talkMonster(objectid, itemId, msg)); broadcastMessage(MobPacket.removeTalkMonster(objectid)); } public final void startMapEffect(String msg, int itemId) { startMapEffect(msg, itemId, false); } public final void startMapEffect(String msg, int itemId, boolean jukebox) { if (this.mapEffect != null) { return; } this.mapEffect = new MapleMapEffect(msg, itemId); this.mapEffect.setJukebox(jukebox); broadcastMessage(this.mapEffect.makeStartData()); Timer.MapTimer.getInstance().schedule(new Runnable() { public void run() { if (MapleMap.this.mapEffect != null) { MapleMap.this.broadcastMessage(MapleMap.this.mapEffect.makeDestroyData()); MapleMap.this.mapEffect = null; } } }, jukebox ? 300000L : 30000L); } public final void startExtendedMapEffect(final String msg, final int itemId) { broadcastMessage(CField.startMapEffect(msg, itemId, true)); Timer.MapTimer.getInstance().schedule(new Runnable() { public void run() { MapleMap.this.broadcastMessage(CField.removeMapEffect()); MapleMap.this.broadcastMessage(CField.startMapEffect(msg, itemId, false)); } }, 60000L); } public final void startSimpleMapEffect(String msg, int itemId) { broadcastMessage(CField.startMapEffect(msg, itemId, true)); } public final void startJukebox(String msg, int itemId) { startMapEffect(msg, itemId, true); } public final void addPlayer(MapleCharacter chr) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.PLAYER)).writeLock().lock(); try { ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.PLAYER)).put(Integer.valueOf(chr.getObjectId()), chr); } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.PLAYER)).writeLock().unlock(); } this.charactersLock.writeLock().lock(); try { this.characters.add(chr); } finally { this.charactersLock.writeLock().unlock(); } chr.setChangeTime(); if ((GameConstants.isTeamMap(this.mapid)) && (!chr.inPVP())) { chr.setTeam(getAndSwitchTeam() ? 0 : 1); } byte[] packet = CField.spawnPlayerMapobject(chr); if (!chr.isHidden()) { broadcastMessage(chr, packet, false); if ((chr.isIntern()) && (this.speedRunStart > 0L)) { endSpeedRun(); broadcastMessage(CWvsContext.serverNotice(5, "The speed run has ended.")); } } else { broadcastGMMessage(chr, packet, false); } if (!chr.isClone()) { if ((!this.onFirstUserEnter.equals("")) && (getCharactersSize() == 1)) { MapScriptMethods.startScript_FirstUser(chr.getClient(), this.onFirstUserEnter); } sendObjectPlacement(chr); chr.getClient().getSession().write(packet); if (!this.onUserEnter.equals("")) { MapScriptMethods.startScript_User(chr.getClient(), this.onUserEnter); } GameConstants.achievementRatio(chr.getClient()); chr.getClient().getSession().write(CField.spawnFlags(this.nodes.getFlags())); if ((GameConstants.isTeamMap(this.mapid)) && (!chr.inPVP())) { chr.getClient().getSession().write(CField.showEquipEffect(chr.getTeam())); } switch (this.mapid) { case 809000101: case 809000201: chr.getClient().getSession().write(CField.showEquipEffect()); break; case 689000000: case 689000010: chr.getClient().getSession().write(CField.getCaptureFlags(this)); } } for (MaplePet pet : chr.getPets()) { if (pet.getSummoned()) { broadcastMessage(chr, PetPacket.showPet(chr, pet, false, false), false); } } if (chr.getSummonedFamiliar() != null) { chr.spawnFamiliar(chr.getSummonedFamiliar(), true); } if (chr.getAndroid() != null) { chr.getAndroid().setPos(chr.getPosition()); broadcastMessage(CField.spawnAndroid(chr, chr.getAndroid())); } if ((chr.getParty() != null) && (!chr.isClone())) { chr.silentPartyUpdate(); chr.getClient().getSession().write(CWvsContext.PartyPacket.updateParty(chr.getClient().getChannel(), chr.getParty(), PartyOperation.SILENT_UPDATE, null)); chr.updatePartyMemberHP(); chr.receivePartyMemberHP(); } if (chr.getDamage() == 696969) { chr.startAutoLooter(); } if ((!chr.isInBlockedMap()) && (chr.getLevel() > 10)) { chr.getClient().getSession().write(CField.getPublicNPCInfo()); } if (GameConstants.isPhantom(chr.getJob())) { chr.getClient().getSession().write(CField.updateCardStack(chr.getCardStack())); } if (!chr.isClone()) { List<MapleSummon> ss = chr.getSummonsReadLock(); try { for (MapleSummon summon : ss) { summon.setPosition(chr.getTruePosition()); chr.addVisibleMapObject(summon); spawnSummon(summon); } } finally { chr.unlockSummonsReadLock(); } } if (this.mapEffect != null) { this.mapEffect.sendStartData(chr.getClient()); } if (timeLimit > 0 && getForcedReturnMap() != null) { chr.startMapTimeLimitTask(timeLimit, getForcedReturnMap()); } if ((chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING) != null) && (!GameConstants.isResist(chr.getJob())) && (FieldLimitType.Mount.check(this.fieldLimit))) { chr.cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING); } if (!chr.isClone()) { if ((chr.getEventInstance() != null) && (chr.getEventInstance().isTimerStarted()) && (!chr.isClone())) { if (chr.inPVP()) { chr.getClient().getSession().write(CField.getPVPClock(Integer.parseInt(chr.getEventInstance().getProperty("type")), (int) (chr.getEventInstance().getTimeLeft() / 1000L))); } else { chr.getClient().getSession().write(CField.getClock((int) (chr.getEventInstance().getTimeLeft() / 1000L))); } } if (hasClock()) { Calendar cal = Calendar.getInstance(); chr.getClient().getSession().write(CField.getClockTime(cal.get(11), cal.get(12), cal.get(13))); } if ((chr.getCarnivalParty() != null) && (chr.getEventInstance() != null)) { chr.getEventInstance().onMapLoad(chr); } if ((getSquadBegin() != null) && (getSquadBegin().getTimeLeft() > 0L) && (getSquadBegin().getStatus() == 1)) { chr.getClient().getSession().write(CField.getClock((int) (getSquadBegin().getTimeLeft() / 1000L))); } if ((this.mapid / 1000 != 105100) && (this.mapid / 100 != 8020003) && (this.mapid / 100 != 8020008) && (this.mapid != 271040100)) { MapleSquad sqd = getSquadByMap(); EventManager em = getEMByMap(); if ((!this.squadTimer) && (sqd != null) && (chr.getName().equals(sqd.getLeaderName())) && (em != null) && (em.getProperty("leader") != null) && (em.getProperty("leader").equals("true")) && (this.checkStates)) { doShrine(false); this.squadTimer = true; } } if ((getNumMonsters() > 0) && ((this.mapid == 280030001) || (this.mapid == 240060201) || (this.mapid == 280030000) || (this.mapid == 240060200) || (this.mapid == 220080001) || (this.mapid == 541020800) || (this.mapid == 541010100))) { String music = "Bgm09/TimeAttack"; switch (this.mapid) { case 240060200: case 240060201: music = "Bgm14/HonTale"; break; case 280030000: case 280030001: music = "Bgm06/FinalFight"; } chr.getClient().getSession().write(CField.musicChange(music)); } for (WeakReference chrz : chr.getClones()) { if (chrz.get() != null) { ((MapleCharacter) chrz.get()).setPosition(chr.getTruePosition()); ((MapleCharacter) chrz.get()).setMap(this); addPlayer((MapleCharacter) chrz.get()); } } if ((this.mapid == 914000000) || (this.mapid == 927000000)) { chr.getClient().getSession().write(CWvsContext.temporaryStats_Aran()); } else if ((this.mapid == 105100300) && (chr.getLevel() >= 91)) { chr.getClient().getSession().write(CWvsContext.temporaryStats_Balrog(chr)); } else if ((this.mapid == 140090000) || (this.mapid == 105100301) || (this.mapid == 105100401) || (this.mapid == 105100100)) { chr.getClient().getSession().write(CWvsContext.temporaryStats_Reset()); } } if ((GameConstants.isEvan(chr.getJob())) && (chr.getJob() >= 2200)) { if (chr.getDragon() == null) { chr.makeDragon(); } else { chr.getDragon().setPosition(chr.getPosition()); } if (chr.getDragon() != null) { broadcastMessage(CField.spawnDragon(chr.getDragon())); } } if (GameConstants.kanna(chr.getJob())) { if (chr.getHaku() == null && chr.getBuffedValue(MapleBuffStat.Haku_Reborn) == null) { chr.makeHaku(); } else { chr.getHaku().setPosition(chr.getPosition()); } if (chr.getHaku() != null) { broadcastMessage(CField.spawnHaku(chr.getHaku())); if (chr.getHaku() != null && chr.getBuffedValue(MapleBuffStat.Haku_Reborn) != null) { chr.getHaku().sendstats(); chr.getMap().broadcastMessage(chr, CField.spawnHaku_change0(chr.getId()), true); chr.getMap().broadcastMessage(chr, CField.spawnHaku_change1(chr.getHaku()), true); chr.getMap().broadcastMessage(chr, CField.spawnHaku_bianshen(chr.getId(), chr.getHaku().getObjectId(), chr.getHaku().getstats()), true); } } } if (this.mapid == 103050900) { try { chr.getClient().getSession().write(CField.UIPacket.IntroEnableUI(1)); chr.getClient().getSession().write(CField.UIPacket.getDirectionInfo(1, 8000)); chr.getClient().getSession().write(CField.UIPacket.getDirectionInfo(1, 8000)); chr.getClient().getSession().write(CField.UIPacket.getDirectionInfo(3, 2)); chr.dropMessage(-1, "On A Rainy Day"); chr.dropMessage(-1, "The Secret Garden Depths"); chr.getClient().removeClickedNPC(); Thread.sleep(11000L); } catch (InterruptedException e) { } chr.getClient().getSession().write(CField.UIPacket.getDirectionStatus(false)); chr.getClient().getSession().write(CField.UIPacket.IntroEnableUI(0)); chr.getClient().removeClickedNPC(); chr.dropMessage(-1, "Click on ryden to get your first quest"); } if (this.permanentWeather > 0) { chr.getClient().getSession().write(CField.startMapEffect("", this.permanentWeather, false)); } if (getPlatforms().size() > 0) { chr.getClient().getSession().write(CField.getMovingPlatforms(this)); } if (this.environment.size() > 0) { chr.getClient().getSession().write(CField.getUpdateEnvironment(this)); } if (isTown()) { chr.cancelEffectFromBuffStat(MapleBuffStat.RAINING_MINES); } if (!canSoar()) { chr.cancelEffectFromBuffStat(MapleBuffStat.SOARING); } if ((chr.getJob() < 3200) || (chr.getJob() > 3212)) { chr.cancelEffectFromBuffStat(MapleBuffStat.AURA); } chr.getClient().getSession().write(CField.NPCPacket.setNPCScriptable(GameConstants.SCRIPTABLE_NPCS)); } public int getNumItems() { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().lock(); try { return ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.ITEM)).size(); } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().unlock(); } } public int getNumMonsters() { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().lock(); try { return ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.MONSTER)).size(); } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().unlock(); } } public void doShrine(final boolean spawned) { if (this.squadSchedule != null) { cancelSquadSchedule(true); } MapleSquad sqd = getSquadByMap(); if (sqd == null) { return; } final int mode = (this.mapid == 240060200) || (this.mapid == 240060201) ? 3 : this.mapid == 280030001 ? 2 : this.mapid == 280030000 ? 1 : 0; EventManager em = getEMByMap(); if ((sqd != null) && (em != null) && (getCharactersSize() > 0)) { final String leaderName = sqd.getLeaderName(); final String state = em.getProperty("state"); MapleMap returnMapa = getForcedReturnMap(); if ((returnMapa == null) || (returnMapa.getId() == this.mapid)) { returnMapa = getReturnMap(); } if ((mode == 1) || (mode == 2)) { broadcastMessage(CField.showChaosZakumShrine(spawned, 5)); } else if (mode == 3) { broadcastMessage(CField.showChaosHorntailShrine(spawned, 5)); } else { broadcastMessage(CField.showHorntailShrine(spawned, 5)); } if (spawned) { broadcastMessage(CField.getClock(60)); } final MapleMap returnMapz = returnMapa; Runnable run; if (!spawned) { final List<MapleMonster> monsterz = getAllMonstersThreadsafe(); final List monsteridz = new ArrayList(); for (MapleMapObject m : monsterz) { monsteridz.add(Integer.valueOf(m.getObjectId())); } run = new Runnable() { public void run() { MapleSquad sqnow = MapleMap.this.getSquadByMap(); if ((MapleMap.this.getCharactersSize() > 0) && (MapleMap.this.getNumMonsters() == monsterz.size()) && (sqnow != null) && (sqnow.getStatus() == 2) && (sqnow.getLeaderName().equals(leaderName)) && (MapleMap.this.getEMByMap().getProperty("state").equals(state))) { boolean passed = monsterz.isEmpty(); for (MapleMapObject m : MapleMap.this.getAllMonstersThreadsafe()) { for (Iterator i$ = monsteridz.iterator(); i$.hasNext();) { int i = ((Integer) i$.next()).intValue(); if (m.getObjectId() == i) { passed = true; break; } } if (passed) { break; } } if (passed) { byte[] packet; if ((mode == 1) || (mode == 2)) { packet = CField.showChaosZakumShrine(spawned, 0); } else { packet = CField.showHorntailShrine(spawned, 0); } for (MapleCharacter chr : MapleMap.this.getCharactersThreadsafe()) { chr.getClient().getSession().write(packet); chr.changeMap(returnMapz, returnMapz.getPortal(0)); } MapleMap.this.checkStates(""); MapleMap.this.resetFully(); } } } }; } else { run = new Runnable() { public void run() { MapleSquad sqnow = MapleMap.this.getSquadByMap(); if ((MapleMap.this.getCharactersSize() > 0) && (sqnow != null) && (sqnow.getStatus() == 2) && (sqnow.getLeaderName().equals(leaderName)) && (MapleMap.this.getEMByMap().getProperty("state").equals(state))) { byte[] packet; if ((mode == 1) || (mode == 2)) { packet = CField.showChaosZakumShrine(spawned, 0); } else { packet = CField.showHorntailShrine(spawned, 0); } for (MapleCharacter chr : MapleMap.this.getCharactersThreadsafe()) { chr.getClient().getSession().write(packet); chr.changeMap(returnMapz, returnMapz.getPortal(0)); } MapleMap.this.checkStates(""); MapleMap.this.resetFully(); } } }; } this.squadSchedule = Timer.MapTimer.getInstance().schedule(run, 300000L); } } public final MapleSquad getSquadByMap() { MapleSquadType zz = null; switch (mapid) { case 105100400: case 105100300: zz = MapleSquadType.bossbalrog; break; case 280030000: zz = MapleSquadType.zak; break; case 280030001: zz = MapleSquadType.chaoszak; break; case 240060200: zz = MapleSquadType.horntail; break; case 240060201: zz = MapleSquadType.chaosht; break; case 270050100: zz = MapleSquadType.pinkbean; break; case 802000111: zz = MapleSquadType.nmm_squad; break; case 802000211: zz = MapleSquadType.vergamot; break; case 802000311: zz = MapleSquadType.tokyo_2095; break; case 802000411: zz = MapleSquadType.dunas; break; case 802000611: zz = MapleSquadType.nibergen_squad; break; case 802000711: zz = MapleSquadType.dunas2; break; case 802000801: case 802000802: case 802000803: zz = MapleSquadType.core_blaze; break; case 802000821: case 802000823: zz = MapleSquadType.aufheben; break; case 211070100: case 211070101: case 211070110: zz = MapleSquadType.vonleon; break; case 551030200: zz = MapleSquadType.scartar; break; case 271040100: zz = MapleSquadType.cygnus; break; default: return null; } return ChannelServer.getInstance(channel).getMapleSquad(zz); } public final MapleSquad getSquadBegin() { if (this.squad != null) { return ChannelServer.getInstance(this.channel).getMapleSquad(this.squad); } return null; } public final EventManager getEMByMap() { String em = null; switch (this.mapid) { case 105100400: em = "BossBalrog_EASY"; break; case 105100300: em = "BossBalrog_NORMAL"; break; case 280030000: em = "ZakumBattle"; break; case 240060200: em = "HorntailBattle"; break; case 280030001: em = "ChaosZakum"; break; case 240060201: em = "ChaosHorntail"; break; case 270050100: em = "PinkBeanBattle"; break; case 802000111: em = "NamelessMagicMonster"; break; case 802000211: em = "Vergamot"; break; case 802000311: em = "2095_tokyo"; break; case 802000411: em = "Dunas"; break; case 802000611: em = "Nibergen"; break; case 802000711: em = "Dunas2"; break; case 802000801: case 802000802: case 802000803: em = "CoreBlaze"; break; case 802000821: case 802000823: em = "Aufhaven"; break; case 211070100: case 211070101: case 211070110: em = "VonLeonBattle"; break; case 551030200: em = "ScarTarBattle"; break; case 271040100: em = "CygnusBattle"; break; case 262031300: em = "HillaBattle"; break; case 272020110: case 272030400: em = "ArkariumBattle"; break; default: return null; } return ChannelServer.getInstance(this.channel).getEventSM().getEventManager(em); } public final void removePlayer(final MapleCharacter chr) { //log.warn("[dc] [level2] Player {} leaves map {}", new Object[] { chr.getName(), mapid }); if (everlast) { returnEverLastItem(chr); } charactersLock.writeLock().lock(); try { characters.remove(chr); } finally { charactersLock.writeLock().unlock(); } removeMapObject(chr); chr.checkFollow(); chr.removeExtractor(); broadcastMessage(CField.removePlayerFromMap(chr.getId())); if (chr.getSummonedFamiliar() != null) { chr.removeVisibleFamiliar(); } if (chr.getDamage() == 696969) { chr.stopAutoLooter(); } List<MapleSummon> toCancel = new ArrayList<MapleSummon>(); final List<MapleSummon> ss = chr.getSummonsReadLock(); try { for (final MapleSummon summon : ss) { broadcastMessage(SummonPacket.removeSummon(summon, true)); removeMapObject(summon); if (summon.getMovementType() == SummonMovementType.STATIONARY || summon.getMovementType() == SummonMovementType.CIRCLE_STATIONARY || summon.getMovementType() == SummonMovementType.WALK_STATIONARY) { toCancel.add(summon); } else { summon.setChangedMap(true); } } } finally { chr.unlockSummonsReadLock(); } for (MapleSummon summon : toCancel) { chr.removeSummon(summon); chr.dispelSkill(summon.getSkill()); //remove the buff } if (!chr.isClone()) { checkStates(chr.getName()); if (mapid == 109020001) { chr.canTalk(true); } for (final WeakReference<MapleCharacter> chrz : chr.getClones()) { if (chrz.get() != null) { removePlayer(chrz.get()); } } chr.leaveMap(this); } } public final void broadcastMessage(byte[] packet) { broadcastMessage(null, packet, (1.0D / 0.0D), null); } public final void broadcastMessage(MapleCharacter source, byte[] packet, boolean repeatToSource) { broadcastMessage(repeatToSource ? null : source, packet, (1.0D / 0.0D), source.getTruePosition()); } public final void broadcastMessage(byte[] packet, Point rangedFrom) { broadcastMessage(null, packet, GameConstants.maxViewRangeSq(), rangedFrom); } public final void broadcastMessage(MapleCharacter source, byte[] packet, Point rangedFrom) { broadcastMessage(source, packet, GameConstants.maxViewRangeSq(), rangedFrom); } public void broadcastMessage(MapleCharacter source, byte[] packet, double rangeSq, Point rangedFrom) { this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if (chr != source) { if (rangeSq < (1.0D / 0.0D)) { if (rangedFrom.distanceSq(chr.getTruePosition()) <= rangeSq) { chr.getClient().getSession().write(packet); } } else { chr.getClient().getSession().write(packet); } } } } finally { this.charactersLock.readLock().unlock(); } } private void sendObjectPlacement(MapleCharacter c) { if ((c == null) || (c.isClone())) { return; } for (MapleMapObject o : getMapObjectsInRange(c.getTruePosition(), c.getRange(), GameConstants.rangedMapobjectTypes)) { if ((o.getType() != MapleMapObjectType.REACTOR) || (((MapleReactor) o).isAlive())) { o.sendSpawnData(c.getClient()); c.addVisibleMapObject(o); } } } public final List<MaplePortal> getPortalsInRange(Point from, double rangeSq) { List ret = new ArrayList(); for (MaplePortal type : this.portals.values()) { if ((from.distanceSq(type.getPosition()) <= rangeSq) && (type.getTargetMapId() != this.mapid) && (type.getTargetMapId() != 999999999)) { ret.add(type); } } return ret; } public final List<MapleMapObject> getMapObjectsInRange(Point from, double rangeSq) { List ret = new ArrayList(); for (MapleMapObjectType type : MapleMapObjectType.values()) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(type)).values().iterator(); while (itr.hasNext()) { MapleMapObject mmo = (MapleMapObject) itr.next(); if (from.distanceSq(mmo.getTruePosition()) <= rangeSq) { ret.add(mmo); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().unlock(); } } return ret; } public List<MapleMapObject> getItemsInRange(Point from, double rangeSq) { return getMapObjectsInRange(from, rangeSq, Arrays.asList(new MapleMapObjectType[]{MapleMapObjectType.ITEM})); } public final List<MapleMapObject> getMapObjectsInRange(Point from, double rangeSq, List<MapleMapObjectType> MapObject_types) { List ret = new ArrayList(); for (MapleMapObjectType type : MapObject_types) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(type)).values().iterator(); while (itr.hasNext()) { MapleMapObject mmo = (MapleMapObject) itr.next(); if (from.distanceSq(mmo.getTruePosition()) <= rangeSq) { ret.add(mmo); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().unlock(); } } return ret; } public final List<MapleMapObject> getMapObjectsInRect(Rectangle box, List<MapleMapObjectType> MapObject_types) { List ret = new ArrayList(); for (MapleMapObjectType type : MapObject_types) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(type)).values().iterator(); while (itr.hasNext()) { MapleMapObject mmo = (MapleMapObject) itr.next(); if (box.contains(mmo.getTruePosition())) { ret.add(mmo); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().unlock(); } } return ret; } public final List<MapleCharacter> getCharactersIntersect(Rectangle box) { List ret = new ArrayList(); this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if (chr.getBounds().intersects(box)) { ret.add(chr); } } } finally { this.charactersLock.readLock().unlock(); } return ret; } public final List<MapleCharacter> getPlayersInRectAndInList(Rectangle box, List<MapleCharacter> chrList) { List character = new LinkedList(); this.charactersLock.readLock().lock(); try { Iterator ltr = this.characters.iterator(); while (ltr.hasNext()) { MapleCharacter a = (MapleCharacter) ltr.next(); if ((chrList.contains(a)) && (box.contains(a.getTruePosition()))) { character.add(a); } } } finally { this.charactersLock.readLock().unlock(); } return character; } public final void addPortal(MaplePortal myPortal) { this.portals.put(Integer.valueOf(myPortal.getId()), myPortal); } public final MaplePortal getPortal(String portalname) { for (MaplePortal port : this.portals.values()) { if (port.getName().equals(portalname)) { return port; } } return null; } public final MaplePortal getPortal(int portalid) { return (MaplePortal) this.portals.get(Integer.valueOf(portalid)); } public final void resetPortals() { for (MaplePortal port : this.portals.values()) { port.setPortalState(true); } } public final void setFootholds(MapleFootholdTree footholds) { this.footholds = footholds; } public final MapleFootholdTree getFootholds() { return this.footholds; } public final int getNumSpawnPoints() { return this.monsterSpawn.size(); } public final void loadMonsterRate(final boolean first) { final int spawnSize = monsterSpawn.size(); if (spawnSize >= 20 || partyBonusRate > 0) { maxRegularSpawn = Math.round(spawnSize / monsterRate); } else { maxRegularSpawn = (int) Math.ceil(spawnSize * monsterRate); } if (fixedMob > 0) { maxRegularSpawn = fixedMob; } else if (maxRegularSpawn <= 2) { maxRegularSpawn = 2; } else if (maxRegularSpawn > spawnSize) { maxRegularSpawn = Math.max(10, spawnSize); } Collection<Spawns> newSpawn = new LinkedList<>(); Collection<Spawns> newBossSpawn = new LinkedList<>(); for (final Spawns s : monsterSpawn) { if (s.getCarnivalTeam() >= 2) { continue; // Remove carnival spawned mobs } if (s.getMonster().isBoss()) { newBossSpawn.add(s); } else { newSpawn.add(s); } } monsterSpawn.clear(); monsterSpawn.addAll(newBossSpawn); monsterSpawn.addAll(newSpawn); if (first && spawnSize > 0) { lastSpawnTime = System.currentTimeMillis(); if (GameConstants.isForceRespawn(mapid)) { createMobInterval = 15000; } respawn(false); // this should do the trick, we don't need to wait upon entering map } } public final SpawnPoint addMonsterSpawn(MapleMonster monster, int mobTime, byte carnivalTeam, String msg) { Point newpos = calcPointBelow(monster.getPosition()); newpos.y -= 1; SpawnPoint sp = new SpawnPoint(monster, newpos, mobTime, carnivalTeam, msg); if (carnivalTeam > -1) { this.monsterSpawn.add(0, sp); } else { this.monsterSpawn.add(sp); } return sp; } public final void addAreaMonsterSpawn(MapleMonster monster, Point pos1, Point pos2, Point pos3, int mobTime, String msg, boolean shouldSpawn) { pos1 = calcPointBelow(pos1); pos2 = calcPointBelow(pos2); pos3 = calcPointBelow(pos3); if (pos1 != null) { pos1.y -= 1; } if (pos2 != null) { pos2.y -= 1; } if (pos3 != null) { pos3.y -= 1; } if ((pos1 == null) && (pos2 == null) && (pos3 == null)) { System.out.println(new StringBuilder().append("WARNING: mapid ").append(this.mapid).append(", monster ").append(monster.getId()).append(" could not be spawned.").toString()); return; } if (pos1 != null) { if (pos2 == null) { pos2 = new Point(pos1); } if (pos3 == null) { pos3 = new Point(pos1); } } else if (pos2 != null) { if (pos1 == null) { pos1 = new Point(pos2); } if (pos3 == null) { pos3 = new Point(pos2); } } else if (pos3 != null) { if (pos1 == null) { pos1 = new Point(pos3); } if (pos2 == null) { pos2 = new Point(pos3); } } this.monsterSpawn.add(new SpawnPointAreaBoss(monster, pos1, pos2, pos3, mobTime, msg, shouldSpawn)); } public final List<MapleCharacter> getCharacters() { return getCharactersThreadsafe(); } public final List<MapleCharacter> getCharactersThreadsafe() { List chars = new ArrayList(); this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { chars.add(mc); } } finally { this.charactersLock.readLock().unlock(); } return chars; } public final MapleCharacter getCharacterByName(String id) { this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { if (mc.getName().equalsIgnoreCase(id)) { return mc; } } } finally { this.charactersLock.readLock().unlock(); } return null; } public final MapleCharacter getCharacterById_InMap(int id) { return getCharacterById(id); } public final MapleCharacter getCharacterById(int id) { this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { if (mc.getId() == id) { return mc; } } } finally { this.charactersLock.readLock().unlock(); } return null; } public final void updateMapObjectVisibility(MapleCharacter chr, MapleMapObject mo) { if ((chr == null) || (chr.isClone())) { return; } if (!chr.isMapObjectVisible(mo)) { if ((mo.getType() == MapleMapObjectType.MIST) || (mo.getType() == MapleMapObjectType.EXTRACTOR) || (mo.getType() == MapleMapObjectType.SUMMON) || (mo.getType() == MapleMapObjectType.FAMILIAR) || ((mo instanceof MechDoor)) || (mo.getTruePosition().distanceSq(chr.getTruePosition()) <= mo.getRange())) { chr.addVisibleMapObject(mo); mo.sendSpawnData(chr.getClient()); } } else if ((!(mo instanceof MechDoor)) && (mo.getType() != MapleMapObjectType.MIST) && (mo.getType() != MapleMapObjectType.EXTRACTOR) && (mo.getType() != MapleMapObjectType.SUMMON) && (mo.getType() != MapleMapObjectType.FAMILIAR) && (mo.getTruePosition().distanceSq(chr.getTruePosition()) > mo.getRange())) { chr.removeVisibleMapObject(mo); mo.sendDestroyData(chr.getClient()); } else if ((mo.getType() == MapleMapObjectType.MONSTER) && (chr.getTruePosition().distanceSq(mo.getTruePosition()) <= GameConstants.maxViewRangeSq_Half())) { updateMonsterController((MapleMonster) mo); } } public void moveMonster(MapleMonster monster, Point reportedPos) { monster.setPosition(reportedPos); this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { updateMapObjectVisibility(mc, monster); } } finally { this.charactersLock.readLock().unlock(); } } public void movePlayer(MapleCharacter player, Point newPosition) { player.setPosition(newPosition); if (!player.isClone()) { try { Collection<MapleMapObject> visibleObjects = player.getAndWriteLockVisibleMapObjects(); ArrayList copy = new ArrayList(visibleObjects); Iterator itr = copy.iterator(); while (itr.hasNext()) { MapleMapObject mo = (MapleMapObject) itr.next(); if ((mo != null) && (getMapObject(mo.getObjectId(), mo.getType()) == mo)) { updateMapObjectVisibility(player, mo); } else if (mo != null) { visibleObjects.remove(mo); } } for (MapleMapObject mo : getMapObjectsInRange(player.getTruePosition(), player.getRange())) { if ((mo != null) && (!visibleObjects.contains(mo))) { mo.sendSpawnData(player.getClient()); visibleObjects.add(mo); } } } finally { Collection visibleObjects; player.unlockWriteVisibleMapObjects(); } } } public MaplePortal findClosestSpawnpoint(Point from) { MaplePortal closest = getPortal(0); double shortestDistance = (1.0D / 0.0D); for (MaplePortal portal : this.portals.values()) { double distance = portal.getPosition().distanceSq(from); if ((portal.getType() >= 0) && (portal.getType() <= 2) && (distance < shortestDistance) && (portal.getTargetMapId() == 999999999)) { closest = portal; shortestDistance = distance; } } return closest; } public MaplePortal findClosestPortal(Point from) { MaplePortal closest = getPortal(0); double shortestDistance = (1.0D / 0.0D); for (MaplePortal portal : this.portals.values()) { double distance = portal.getPosition().distanceSq(from); if (distance < shortestDistance) { closest = portal; shortestDistance = distance; } } return closest; } public String spawnDebug() { StringBuilder sb = new StringBuilder("Mobs in map : "); sb.append(getMobsSize()); sb.append(" spawnedMonstersOnMap: "); sb.append(this.spawnedMonstersOnMap); sb.append(" spawnpoints: "); sb.append(this.monsterSpawn.size()); sb.append(" maxRegularSpawn: "); sb.append(this.maxRegularSpawn); sb.append(" actual monsters: "); sb.append(getNumMonsters()); sb.append(" monster rate: "); sb.append(this.monsterRate); sb.append(" fixed: "); sb.append(this.fixedMob); return sb.toString(); } public int characterSize() { return this.characters.size(); } public final int getMapObjectSize() { return this.mapobjects.size() + getCharactersSize() - this.characters.size(); } public final int getCharactersSize() { int ret = 0; this.charactersLock.readLock().lock(); try { Iterator ltr = this.characters.iterator(); while (ltr.hasNext()) { MapleCharacter chr = (MapleCharacter) ltr.next(); if (!chr.isClone()) { ret++; } } } finally { this.charactersLock.readLock().unlock(); } return ret; } public Collection<MaplePortal> getPortals() { return Collections.unmodifiableCollection(this.portals.values()); } public int getSpawnedMonstersOnMap() { return this.spawnedMonstersOnMap.get(); } public void spawnMonsterOnGroudBelow(MapleMonster mob, Point pos) { spawnMonsterOnGroundBelow(mob, pos); } public void respawn(boolean force) { respawn(force, System.currentTimeMillis()); } public void respawn(boolean force, long now) { this.lastSpawnTime = now; int numShouldSpawn; int spawned; if (force) { numShouldSpawn = this.monsterSpawn.size() - this.spawnedMonstersOnMap.get(); if (numShouldSpawn > 0) { spawned = 0; for (Spawns spawnPoint : this.monsterSpawn) { spawnPoint.spawnMonster(this); spawned++; if (spawned >= numShouldSpawn) { break; } } } } else { numShouldSpawn = (GameConstants.isForceRespawn(this.mapid) ? this.monsterSpawn.size() : this.maxRegularSpawn) - this.spawnedMonstersOnMap.get(); if (numShouldSpawn > 0) { spawned = 0; List<Spawns> randomSpawn = new ArrayList(this.monsterSpawn); Collections.shuffle(randomSpawn); for (Spawns spawnPoint : randomSpawn) { if ((this.isSpawns) || (spawnPoint.getMobTime() <= 0)) { if ((spawnPoint.shouldSpawn(this.lastSpawnTime)) || (GameConstants.isForceRespawn(this.mapid)) || ((this.monsterSpawn.size() < 10) && (this.maxRegularSpawn > this.monsterSpawn.size()) && (this.partyBonusRate > 0))) { spawnPoint.spawnMonster(this); spawned++; } if (spawned >= numShouldSpawn) { break; } } } } } } public String getSnowballPortal() { int[] teamss = new int[2]; this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if (chr.getTruePosition().y > -80) { teamss[0] += 1; } else { teamss[1] += 1; } } } finally { this.charactersLock.readLock().unlock(); } if (teamss[0] > teamss[1]) { return "st01"; } return "st00"; } public boolean isDisconnected(int id) { return this.dced.contains(Integer.valueOf(id)); } public void addDisconnected(int id) { this.dced.add(Integer.valueOf(id)); } public void resetDisconnected() { this.dced.clear(); } public void startSpeedRun() { final MapleSquad squad = getSquadByMap(); if (squad != null) { charactersLock.readLock().lock(); try { for (MapleCharacter chr : characters) { if (chr.getName().equals(squad.getLeaderName()) && !chr.isIntern()) { startSpeedRun(chr.getName()); return; } } } finally { charactersLock.readLock().unlock(); } } } public void startSpeedRun(String leader) { this.speedRunStart = System.currentTimeMillis(); this.speedRunLeader = leader; } public void endSpeedRun() { this.speedRunStart = 0L; this.speedRunLeader = ""; } public void clearDrops(MapleCharacter player, boolean drops) { List<MapleMapObject> items = player.getMap().getMapObjectsInRange(player.getPosition(), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.ITEM)); for (MapleMapObject i : items) { player.getMap().removeMapObject(i); player.getMap().broadcastMessage(CField.removeItemFromMap(i.getObjectId(), 0, player.getId())); } if (drops) {//if drops = true player.dropMessage(6, "Cleared " + items.size() + " Drops"); } } public void getRankAndAdd(String leader, String time, ExpeditionType type, long timz, Collection<String> squad) { try { long lastTime = SpeedRunner.getSpeedRunData(type) == null ? 0L : ((Long) SpeedRunner.getSpeedRunData(type).right).longValue(); StringBuilder rett = new StringBuilder(); if (squad != null) { for (String chr : squad) { rett.append(chr); rett.append(","); } } String z = rett.toString(); if (squad != null) { z = z.substring(0, z.length() - 1); } Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("INSERT INTO speedruns(`type`, `leader`, `timestring`, `time`, `members`) VALUES (?,?,?,?,?)"); ps.setString(1, type.name()); ps.setString(2, leader); ps.setString(3, time); ps.setLong(4, timz); ps.setString(5, z); ps.executeUpdate(); ps.close(); if (lastTime == 0L) { SpeedRunner.addSpeedRunData(type, SpeedRunner.addSpeedRunData(new StringBuilder(SpeedRunner.getPreamble(type)), new HashMap(), z, leader, 1, time), timz); } else { SpeedRunner.removeSpeedRunData(type); SpeedRunner.loadSpeedRunData(type); } } catch (Exception e) { e.printStackTrace(); } } public long getSpeedRunStart() { return this.speedRunStart; } public final void disconnectAll() { for (MapleCharacter chr : getCharactersThreadsafe()) { if (!chr.isGM()) { chr.getClient().disconnect(true, false); chr.getClient().getSession().close(true); } } } public List<MapleNPC> getAllNPCs() { return getAllNPCsThreadsafe(); } public List<MapleNPC> getAllNPCsThreadsafe() { ArrayList<MapleNPC> ret = new ArrayList<MapleNPC>(); mapobjectlocks.get(MapleMapObjectType.NPC).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.NPC).values()) { ret.add((MapleNPC) mmo); } } finally { mapobjectlocks.get(MapleMapObjectType.NPC).readLock().unlock(); } return ret; } public final void resetNPCs() { removeNpc(-1); } public final void resetPQ(int level) { resetFully(); for (MapleMonster mons : getAllMonstersThreadsafe()) { mons.changeLevel(level, true); } resetSpawnLevel(level); } public final void resetSpawnLevel(int level) { for (Spawns spawn : this.monsterSpawn) { if ((spawn instanceof SpawnPoint)) { ((SpawnPoint) spawn).setLevel(level); } } } public final void resetFully() { resetFully(true); } public final void resetFully(boolean respawn) { killAllMonsters(false); reloadReactors(); removeDrops(); resetNPCs(); resetSpawns(); resetDisconnected(); endSpeedRun(); cancelSquadSchedule(true); resetPortals(); this.environment.clear(); if (respawn) { respawn(true); } } public final void cancelSquadSchedule(boolean interrupt) { this.squadTimer = false; this.checkStates = true; if (this.squadSchedule != null) { this.squadSchedule.cancel(interrupt); this.squadSchedule = null; } } public final void removeDrops() { final List<MapleMapItem> items = getAllItemsThreadsafe(); for (MapleMapItem i : items) { i.expire(this); } } public final void resetAllSpawnPoint(int mobid, int mobTime) { Collection<Spawns> sss = new LinkedList(this.monsterSpawn); resetFully(); this.monsterSpawn.clear(); for (Spawns s : sss) { MapleMonster newMons = MapleLifeFactory.getMonster(mobid); newMons.setF(s.getF()); newMons.setFh(s.getFh()); newMons.setPosition(s.getPosition()); addMonsterSpawn(newMons, mobTime, (byte) -1, null); } loadMonsterRate(true); } public final void resetSpawns() { boolean changed = false; Iterator sss = this.monsterSpawn.iterator(); while (sss.hasNext()) { if (((Spawns) sss.next()).getCarnivalId() > -1) { sss.remove(); changed = true; } } setSpawns(true); if (changed) { loadMonsterRate(true); } } public final boolean makeCarnivalSpawn(int team, MapleMonster newMons, int num) { MapleNodes.MonsterPoint ret = null; for (MapleNodes.MonsterPoint mp : this.nodes.getMonsterPoints()) { if ((mp.team == team) || (mp.team == -1)) { Point newpos = calcPointBelow(new Point(mp.x, mp.y)); newpos.y -= 1; boolean found = false; for (Spawns s : this.monsterSpawn) { if ((s.getCarnivalId() > -1) && ((mp.team == -1) || (s.getCarnivalTeam() == mp.team)) && (s.getPosition().x == newpos.x) && (s.getPosition().y == newpos.y)) { found = true; break; } } if (!found) { ret = mp; break; } } } if (ret != null) { newMons.setCy(ret.cy); newMons.setF(0); newMons.setFh(ret.fh); newMons.setRx0(ret.x + 50); newMons.setRx1(ret.x - 50); newMons.setPosition(new Point(ret.x, ret.y)); newMons.setHide(false); SpawnPoint sp = addMonsterSpawn(newMons, 1, (byte) team, null); sp.setCarnival(num); } return ret != null; } public final boolean makeCarnivalReactor(int team, int num) { MapleReactor old = getReactorByName(new StringBuilder().append(team).append("").append(num).toString()); if ((old != null) && (old.getState() < 5)) { return false; } Point guardz = null; List<MapleReactor> react = getAllReactorsThreadsafe(); for (Pair guard : this.nodes.getGuardians()) { if ((((Integer) guard.right).intValue() == team) || (((Integer) guard.right).intValue() == -1)) { boolean found = false; for (MapleReactor r : react) { if ((r.getTruePosition().x == ((Point) guard.left).x) && (r.getTruePosition().y == ((Point) guard.left).y) && (r.getState() < 5)) { found = true; break; } } if (!found) { guardz = (Point) guard.left; break; } } } MapleCarnivalFactory.MCSkill skil; if (guardz != null) { MapleReactor my = new MapleReactor(MapleReactorFactory.getReactor(9980000 + team), 9980000 + team); my.setState((byte) 1); my.setName(new StringBuilder().append(team).append("").append(num).toString()); spawnReactorOnGroundBelow(my, guardz); skil = MapleCarnivalFactory.getInstance().getGuardian(num); for (MapleMonster mons : getAllMonstersThreadsafe()) { if (mons.getCarnivalTeam() == team) { skil.getSkill().applyEffect(null, mons, false); } } } return guardz != null; } public final void blockAllPortal() { for (MaplePortal p : this.portals.values()) { p.setPortalState(false); } } public boolean getAndSwitchTeam() { return getCharactersSize() % 2 != 0; } public void setSquad(MapleSquad.MapleSquadType s) { this.squad = s; } public int getChannel() { return this.channel; } public int getConsumeItemCoolTime() { return this.consumeItemCoolTime; } public void setConsumeItemCoolTime(int ciit) { this.consumeItemCoolTime = ciit; } public void setPermanentWeather(int pw) { this.permanentWeather = pw; } public int getPermanentWeather() { return this.permanentWeather; } public void checkStates(String chr) { if (!this.checkStates) { return; } MapleSquad sqd = getSquadByMap(); EventManager em = getEMByMap(); int size = getCharactersSize(); if ((sqd != null) && (sqd.getStatus() == 2)) { sqd.removeMember(chr); if (em != null) { if (sqd.getLeaderName().equalsIgnoreCase(chr)) { em.setProperty("leader", "false"); } if ((chr.equals("")) || (size == 0)) { em.setProperty("state", "0"); em.setProperty("leader", "true"); cancelSquadSchedule(!chr.equals("")); sqd.clear(); sqd.copy(); } } } if ((em != null) && (em.getProperty("state") != null) && ((sqd == null) || (sqd.getStatus() == 2)) && (size == 0)) { em.setProperty("state", "0"); if (em.getProperty("leader") != null) { em.setProperty("leader", "true"); } } if ((this.speedRunStart > 0L) && (size == 0)) { endSpeedRun(); } } public void setCheckStates(boolean b) { this.checkStates = b; } public void setNodes(MapleNodes mn) { this.nodes = mn; } public final List<MapleNodes.MaplePlatform> getPlatforms() { return this.nodes.getPlatforms(); } public Collection<MapleNodes.MapleNodeInfo> getNodes() { return this.nodes.getNodes(); } public MapleNodes.MapleNodeInfo getNode(int index) { return this.nodes.getNode(index); } public boolean isLastNode(int index) { return this.nodes.isLastNode(index); } public final List<Rectangle> getAreas() { return this.nodes.getAreas(); } public final Rectangle getArea(int index) { return this.nodes.getArea(index); } public final void changeEnvironment(String ms, int type) { broadcastMessage(CField.environmentChange(ms, type)); } public final void toggleEnvironment(String ms) { if (this.environment.containsKey(ms)) { moveEnvironment(ms, ((Integer) this.environment.get(ms)).intValue() == 1 ? 2 : 1); } else { moveEnvironment(ms, 1); } } public final void moveEnvironment(String ms, int type) { broadcastMessage(CField.environmentMove(ms, type)); this.environment.put(ms, Integer.valueOf(type)); } public final Map<String, Integer> getEnvironment() { return this.environment; } public final int getNumPlayersInArea(int index) { return getNumPlayersInRect(getArea(index)); } public final int getNumPlayersInRect(Rectangle rect) { int ret = 0; this.charactersLock.readLock().lock(); try { Iterator ltr = this.characters.iterator(); while (ltr.hasNext()) { if (rect.contains(((MapleCharacter) ltr.next()).getTruePosition())) { ret++; } } } finally { this.charactersLock.readLock().unlock(); } return ret; } public final int getNumPlayersItemsInArea(int index) { return getNumPlayersItemsInRect(getArea(index)); } public final MapleCharacter getPlayer() { return this.c.getPlayer(); } public final int getNumPlayersItemsInRect(final Rectangle rect) { int ret = getNumPlayersInRect(rect); mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.ITEM).values()) { if (rect.contains(mmo.getTruePosition())) { ret++; } } } finally { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().unlock(); } return ret; } public void broadcastGMMessage(MapleCharacter source, byte[] packet, boolean repeatToSource) { broadcastGMMessage(repeatToSource ? null : source, packet); } private void broadcastGMMessage(MapleCharacter source, byte[] packet) { this.charactersLock.readLock().lock(); try { if (source == null) { for (MapleCharacter chr : this.characters) { if (chr.isStaff()) { chr.getClient().getSession().write(packet); } } } else { for (MapleCharacter chr : this.characters) { if ((chr != source) && (chr.getGMLevel() >= source.getGMLevel())) { chr.getClient().getSession().write(packet); } } } } finally { this.charactersLock.readLock().unlock(); } } public final List<Pair<Integer, Integer>> getMobsToSpawn() { return this.nodes.getMobsToSpawn(); } public final List<Integer> getSkillIds() { return this.nodes.getSkillIds(); } public final boolean canSpawn(long now) { return (this.lastSpawnTime > 0L) && (this.lastSpawnTime + this.createMobInterval < now); } public final boolean canHurt(long now) { if ((this.lastHurtTime > 0L) && (this.lastHurtTime + this.decHPInterval < now)) { this.lastHurtTime = now; return true; } return false; } public final void resetShammos(final MapleClient c) { killAllMonsters(true); broadcastMessage(CWvsContext.serverNotice(5, "A player has moved too far from Shammos. Shammos is going back to the start.")); Timer.EtcTimer.getInstance().schedule(new Runnable() { public void run() { if (c.getPlayer() != null) { c.getPlayer().changeMap(MapleMap.this, MapleMap.this.getPortal(0)); if (MapleMap.this.getCharactersThreadsafe().size() > 1) { MapScriptMethods.startScript_FirstUser(c, "shammos_Fenter"); } } } }, 500L); } public int getInstanceId() { return this.instanceid; } public void setInstanceId(int ii) { this.instanceid = ii; } public int getPartyBonusRate() { return this.partyBonusRate; } public void setPartyBonusRate(int ii) { this.partyBonusRate = ii; } public short getTop() { return this.top; } public short getBottom() { return this.bottom; } public short getLeft() { return this.left; } public short getRight() { return this.right; } public void setTop(int ii) { this.top = ((short) ii); } public void setBottom(int ii) { this.bottom = ((short) ii); } public void setLeft(int ii) { this.left = ((short) ii); } public void setRight(int ii) { this.right = ((short) ii); } public final void setChangeableMobOrigin(MapleCharacter d) { this.changeMobOrigin = new WeakReference(d); } public final MapleCharacter getChangeableMobOrigin() { if (this.changeMobOrigin == null) { return null; } return (MapleCharacter) this.changeMobOrigin.get(); } public List<Pair<Point, Integer>> getGuardians() { return this.nodes.getGuardians(); } public MapleNodes.DirectionInfo getDirectionInfo(int i) { return this.nodes.getDirection(i); } public final void spawnTutorialDrop() { if (mapobjects.get(MapleMapObjectType.ITEM).size() >= 3) { return; } if (mapid != TutorialConstants.tutorialDropsMap) { return; } mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().lock(); try { for (MapleMapObject o : mapobjects.get(MapleMapObjectType.ITEM).values()) { if (((MapleMapItem) o).isRandDrop()) { // this is to show that 1 item has already been dropped before return; } } } finally { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().unlock(); } final Point pos = new Point(TutorialConstants.dropPosX, TutorialConstants.dropPosY); // change to the position you want to final int[] itemid = null; if (mapid == TutorialConstants.tutorialDropsMap) { if (itemid != null) { spawnAutoDrop(TutorialConstants.tutorialDrops[Randomizer.nextInt(TutorialConstants.tutorialDrops.length)], pos); } spawnAutoDrop(TutorialConstants.tutorialDrops[Randomizer.nextInt(TutorialConstants.tutorialDrops.length)], pos); } } public boolean getMuted() { return muted; } public void setMuted(boolean isMuted) { this.muted = isMuted; } public final MapleMapObject getClosestMapObjectInRange(Point from, double rangeSq, List<MapleMapObjectType> MapObject_types) { MapleMapObject ret = null; for (MapleMapObjectType type : MapObject_types) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().lock(); try { Iterator itr = ((LinkedHashMap) this.mapobjects.get(type)).values().iterator(); while (itr.hasNext()) { MapleMapObject mmo = (MapleMapObject) itr.next(); if ((from.distanceSq(mmo.getTruePosition()) <= rangeSq) && ((ret == null) || (from.distanceSq(ret.getTruePosition()) > from.distanceSq(mmo.getTruePosition())))) { ret = mmo; } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(type)).readLock().unlock(); } } return ret; } private static abstract interface DelayedPacketCreation { public abstract void sendPackets(MapleClient paramMapleClient); } private class ActivateItemReactor implements Runnable { private MapleMapItem mapitem; private MapleReactor reactor; private MapleClient c; public ActivateItemReactor(MapleMapItem mapitem, MapleReactor reactor, MapleClient c) { this.mapitem = mapitem; this.reactor = reactor; this.c = c; } public void run() { if ((this.mapitem != null) && (this.mapitem == MapleMap.this.getMapObject(this.mapitem.getObjectId(), this.mapitem.getType())) && (!this.mapitem.isPickedUp())) { this.mapitem.expire(MapleMap.this); this.reactor.hitReactor(this.c); this.reactor.setTimerActive(false); if (this.reactor.getDelay() > 0) { Timer.MapTimer.getInstance().schedule(new Runnable() { public void run() { MapleMap.ActivateItemReactor.this.reactor.forceHitReactor((byte) 0); } }, this.reactor.getDelay()); } } else { this.reactor.setTimerActive(false); } } } }