package server.maps; import client.MapleBuffStat; import client.MapleCharacter; import client.MapleClient; import client.MonsterFamiliar; import client.Skill; import client.SkillFactory; 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.ItemConstants; import constants.ServerConstants; import database.DatabaseConnection; import handling.channel.ChannelServer; import handling.world.PartyOperation; import handling.world.WorldBroadcastService; import handling.world.party.ExpeditionType; import handling.world.party.MaplePartyCharacter; import java.awt.Point; import java.awt.Rectangle; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; 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.Random; import java.util.TimerTask; 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.event.EventManager; import server.MapleCarnivalFactory; import server.MapleInventoryManipulator; import server.MapleItemInformationProvider; import server.MaplePortal; import server.MapleStatEffect; import server.Randomizer; import server.SpeedRunner; import server.Timer.EtcTimer; import server.Timer.MapTimer; import server.events.MapleEvent; 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 server.squad.MapleSquad; import server.squad.MapleSquadType; import tools.FileoutputUtil; import tools.MaplePacketCreator; import tools.Pair; import tools.StringUtil; import tools.packet.BuffPacket; import tools.packet.InventoryPacket; import tools.packet.MobPacket; import tools.packet.NPCPacket; import tools.packet.PartyPacket; import tools.packet.PetPacket; import tools.packet.SkillPacket; import tools.packet.SummonPacket; import tools.packet.UIPacket; 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 final AtomicInteger runningOid = new AtomicInteger(100000); private final Lock runningOidLock = new ReentrantLock(true); 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 final float monsterRate; private float recoveryRate; private MapleMapEffect mapEffect; private final int channel; private short decHP = 0; // 地图自动掉血值 private int decHPInterval = 10000; // 地图自动掉血间隔 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 final int mapid; private int returnMapId; private int timeLimit; 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 boat; private boolean docked; 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 final List<Integer> dced = new ArrayList(); private List<Point> spawnPoints = new ArrayList(); private ScheduledFuture<?> squadSchedule; private long speedRunStart = 0; private long lastSpawnTime = 0; private long lastHurtTime = 0; private MapleNodes nodes; private MapleSquadType squad; private final Map<String, Integer> environment = new LinkedHashMap(); private long runeTine = 0; private boolean special = false; public MapleMap(int mapid, int channel, int returnMapId, float monsterRate) { this.mapid = mapid; this.channel = channel; this.returnMapId = returnMapId; if (this.returnMapId == 999999999) { this.returnMapId = mapid; } special = mapid == 105200510; 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 void setSpawns(boolean fm) { this.isSpawns = fm; } public boolean getSpawns() { return this.isSpawns; } public boolean getSpecial() { return this.special; } public void setFixedMob(int fm) { this.fixedMob = fm; } public void setForceMove(int fm) { this.lvForceMove = fm; } public int getForceMove() { return this.lvForceMove; } public void setLevelLimit(int fm) { this.lvLimit = fm; } public int getLevelLimit() { return this.lvLimit; } public void setReturnMapId(int rmi) { this.returnMapId = rmi; } public void setSoaring(boolean b) { this.soaring = b; } public boolean canSoar() { return this.soaring; } public void toggleDrops() { this.dropsDisabled = (!this.dropsDisabled); } public void setDrops(boolean b) { this.dropsDisabled = b; } public void toggleGDrops() { this.gDropsDisabled = (!this.gDropsDisabled); } public int getId() { return this.mapid; } public MapleMap getReturnMap() { return ChannelServer.getInstance(this.channel).getMapFactory().getMap(this.returnMapId); } public int getReturnMapId() { return this.returnMapId; } public int getForcedReturnId() { return this.forcedReturnMap; } public MapleMap getForcedReturnMap() { return ChannelServer.getInstance(this.channel).getMapFactory().getMap(this.forcedReturnMap); } public void setForcedReturnMap(int map) { this.forcedReturnMap = map; } public float getRecoveryRate() { return this.recoveryRate; } public void setRecoveryRate(float recoveryRate) { this.recoveryRate = recoveryRate; } public int getFieldLimit() { return this.fieldLimit; } public void setFieldLimit(int fieldLimit) { this.fieldLimit = fieldLimit; } public void setCreateMobInterval(short createMobInterval) { this.createMobInterval = createMobInterval; } public void setTimeLimit(int timeLimit) { this.timeLimit = timeLimit; } public void setMapName(String mapName) { this.mapName = mapName; } public String getMapName() { return this.mapName; } public String getStreetName() { return this.streetName; } public void setFirstUserEnter(String onFirstUserEnter) { this.onFirstUserEnter = onFirstUserEnter; } public void setUserEnter(String onUserEnter) { this.onUserEnter = onUserEnter; } public String getFirstUserEnter() { return this.onFirstUserEnter; } public String getUserEnter() { return this.onUserEnter; } public boolean hasClock() { return this.clock; } public void setClock(boolean hasClock) { this.clock = hasClock; } public boolean isTown() { return this.town; } public void setTown(boolean town) { this.town = town; } public boolean allowPersonalShop() { return this.personalShop; } public void setPersonalShop(boolean personalShop) { this.personalShop = personalShop; } public void setStreetName(String streetName) { this.streetName = streetName; } public void setEverlast(boolean everlast) { this.everlast = everlast; } public boolean getEverlast() { return this.everlast; } public int getHPDec() { return this.decHP; } public void setHPDec(int delta) { if ((delta > 0) || (this.mapid == 749040100)) { this.lastHurtTime = System.currentTimeMillis(); } this.decHP = (short) delta; } public int getHPDecInterval() { return this.decHPInterval; } public void setHPDecInterval(int delta) { this.decHPInterval = delta; } public int getHPDecProtect() { return this.protectItem; } public void setHPDecProtect(int delta) { this.protectItem = delta; } public void setSpawnPoints(List<Point> Points) { this.spawnPoints = Points; } public List<Point> getSpawnPoints() { return this.spawnPoints; } public int getCurrentPartyId() { this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if (chr.getParty() != null) { int i = chr.getParty().getId(); return i; } } } finally { this.charactersLock.readLock().unlock(); } return -1; } public void addMapObject(MapleMapObject mapobject) { this.runningOidLock.lock(); try { if (mapobject.getObjectId() != 0) { mapobject.setObjectId(mapobject.getObjectId()); } else { mapobject.setObjectId(runningOid.getAndIncrement()); } } finally { this.runningOidLock.unlock(); } ReentrantReadWriteLock rl = this.mapobjectlocks.get(mapobject.getType()); rl.writeLock().lock(); try { ((LinkedHashMap) this.mapobjects.get(mapobject.getType())).put(mapobject.getObjectId(), mapobject); } finally { rl.writeLock().unlock(); } } private void spawnAndAddRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery) { addMapObject(mapobject); this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if ((mapobject.getType() == MapleMapObjectType.MIST) || (chr.getTruePosition().distance(mapobject.getTruePosition()) <= GameConstants.maxViewRangeSq())) { packetbakery.sendPackets(chr.getClient()); chr.addVisibleMapObject(mapobject); } } } finally { this.charactersLock.readLock().unlock(); } } public void removeMapObject(MapleMapObject obj) { ReentrantReadWriteLock rl = this.mapobjectlocks.get(obj.getType()); rl.writeLock().lock(); try { ((LinkedHashMap) this.mapobjects.get(obj.getType())).remove(obj.getObjectId()); } finally { rl.writeLock().unlock(); } } public 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()); double s5 = Math.cos(Math.atan(s2 / s1)) * (Math.abs(initial.x - fh.getX1()) / Math.cos(Math.atan(s1 / s2))); if (fh.getY2() < fh.getY1()) { dropY = fh.getY1() - (int) s5; } else { dropY = fh.getY1() + (int) s5; } } return new Point(initial.x, dropY); } public Point calcDropPos(Point initial, Point fallback) { Point ret = calcPointBelow(new Point(initial.x, initial.y - 99)); if (ret == null) { return fallback; } return ret; } private void dropFromMonster(MapleCharacter chr, MapleMonster mob, boolean instanced) {//TODO 怪物死亡掉落物品 if (mob == null) { chr.dropMessage(1,"怪物为空了!"); return; } if (chr == null) { chr.dropMessage(1,"角色为空了!"); return; } if ((ChannelServer.getInstance(this.channel) == null) ) { chr.dropMessage(1,"频道为空了!"); return; } // if ((this.dropsDisabled)) { // chr.dropMessage(1,"该地图不能掉落道具"); // return; // } if ((mob.dropsDisabled())) { chr.dropMessage(1,"怪物不能掉落道具:"+mob.getId()); return; } int maxSize = 200; if ((!instanced) && (maxSize >= 300) && (((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.ITEM)).size() >= maxSize)) { removeDropsDelay(); if (chr.isShowPacket()) { chr.dropMessage(6, new StringBuilder().append("[系统提示] 当前地图的道具数量达到 ").append(maxSize).append(" 系统已自动清理掉所有地上的物品信息.").toString()); } } MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); byte droptype = (byte) (chr.getParty() != null ? 1 : mob.getStats().isFfaLoot() ? 2 : mob.getStats().isExplosiveReward() ? 3 : 0); int mobpos = mob.getTruePosition().x; int mesoServerRate = ChannelServer.getInstance(this.channel).getMesoRate(chr.getWorld()); int dropServerRate = ChannelServer.getInstance(this.channel).getDropRate(chr.getWorld()); int cashServerRate = ChannelServer.getInstance(this.channel).getCashRate(); int globalServerRate = ChannelServer.getInstance(this.channel).getGlobalRate(); byte d = 1; Point pos = new Point(0, mob.getTruePosition().y); MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance(); List derp = mi.retrieveDrop(mob.getId()); if (derp == null) { FileoutputUtil.log("找不到怪物的掉落:"+mob.getId()); return; } List<MonsterDropEntry> dropEntry = new ArrayList(derp); Collections.shuffle(dropEntry); for (MonsterDropEntry de : dropEntry) { if (de.itemId == mob.getStolen()) { continue; } if (Randomizer.nextInt(10000) < (int) (de.chance * dropServerRate * chr.getDropMod() * (chr.getStat().getDropBuff() / 100.0D))) { if (((droptype != 3) && (de.itemId == 0))) { continue; } // if (droptype == 3) { // pos.x = (mobpos + (d % 2 == 0 ? 40 * (d + 1) / 2 : -(40 * (d / 2)))); // } else { pos.x = Math.min(Math.max(mobpos - 25 * (d / 2), footholds.getMinDropX() + 25),footholds.getMaxDropX() - d * 25); // pos.x = (mobpos + (d % 2 == 0 ? 25 * (d + 1) / 2 : -(25 * (d / 2)))); // } if (de.itemId > 0) { Item idrop; if (ItemConstants.getInventoryType(de.itemId) == MapleInventoryType.EQUIP) { idrop = ii.randomizeStats((Equip) ii.getEquipById(de.itemId)); } else { 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), (short) 0); } idrop.setGMLog(new StringBuilder().append("怪物掉落: ").append(mob.getId()).append(" 地图: ").append(this.mapid).append(" 时间: ").append(FileoutputUtil.CurrentReadable_Date()).toString()); if (ItemConstants.isNoticeItem(de.itemId)) { broadcastMessage(MaplePacketCreator.serverMessageNotice(new StringBuilder(127).append("\"").append(chr.getName()).append("\" 在\"").append(chr.getMap().getMapName()).append("\"杀死\"").append(mob.getStats().getName()).append("\",掉落道具\"").append(ii.getName(de.itemId)).append("\"").toString())); } spawnMobDrop(idrop, calcDropPos(pos, mob.getTruePosition()), mob, chr, droptype, de.questid); } d++; } } d++; pos.x = Math.min(Math.max(mobpos - 25 * (d / 2), footholds.getMinDropX() + 25),footholds.getMaxDropX() - d * 25); int mesos = Randomizer.nextInt(mob.getMobLevel() * 10) + mob.getMobLevel(); if (mesos > 0) { spawnMobMesoDrop((int) (mesos * (chr.getStat().mesoBuff / 100.0D) * chr.getDropMod() * mesoServerRate), calcDropPos(pos, mob.getTruePosition()), mob, chr, false, droptype); } List<MonsterGlobalDropEntry> globalEntry = new ArrayList(mi.getGlobalDrop()); Collections.shuffle(globalEntry); int cashz = ((mob.getStats().isBoss()) && (mob.getStats().getHPDisplayType() == 0) ? 20 : 1) * cashServerRate; int cashModifier = (int) (mob.getStats().isBoss() ? mob.getStats().isPartyBonus() ? mob.getMobExp() / 1000 : 0 : mob.getMobExp() / 1000 + mob.getMobMaxHp() / 20000L); for (MonsterGlobalDropEntry de : globalEntry) { if (de.chance == 0) { continue; } if ((Randomizer.nextInt(GameConstants.DROP_ITEM_PER) < de.chance * globalServerRate) && ((de.continent < 0) || ((de.continent < 10) && (this.mapid / 100000000 == de.continent)) || ((de.continent < 100) && (this.mapid / 10000000 == de.continent)) || ((de.continent < 1000) && (this.mapid / 1000000 == de.continent)))) { if ((de.itemId == 0) && (cashServerRate != 0)) { int giveCash = Randomizer.nextInt(cashz) + cashz + cashModifier; if (giveCash > 0) { chr.modifyCSPoints(2, giveCash, true); } } else if (!this.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)))); } Item idrop; if (ItemConstants.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), (short) 0); } idrop.setGMLog(new StringBuilder().append("怪物掉落: ").append(mob.getId()).append(" 地图: ").append(this.mapid).append(" (Global) 时间: ").append(FileoutputUtil.CurrentReadable_Date()).toString()); if (ItemConstants.isNoticeItem(de.itemId)) { broadcastMessage(MaplePacketCreator.serverMessageNotice(new StringBuilder(127).append("\"").append(chr.getName()).append("\" 在\"").append(chr.getMap().getMapName()).append("\"杀死\" ").append(mob.getStats().getName()).append("\",掉落道具\"").append(ii.getName(de.itemId)).append("\"").toString())); } 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) { if (monster == null) { return; } this.spawnedMonstersOnMap.decrementAndGet(); monster.setHp(0L); final java.util.Timer timer = new java.util.Timer(true); TimerTask task = new TimerTask() { @Override public void run() { if (monster.getLinkCID() <= 0) { monster.spawnRevives(monster.getMap()); } timer.cancel(); } }; if (monster.getId() == 8820108 || monster.getId() == 8810026 || monster.getId() == 8820108 || monster.getId() == 8810130 || monster.getId() == 8820008) { timer.schedule(task, 4500); } else { if (monster.getLinkCID() <= 0) { monster.spawnRevives(monster.getMap()); } } broadcastMessage(MobPacket.killMonster(monster.getObjectId(), monster.getStats().getSelfD() < 0 ? 1 : monster.getStats().getSelfD())); removeMapObject(monster); monster.killed(); } public void killMonster(MapleMonster monster, MapleCharacter chr, boolean withDrops, boolean second, byte animation) { killMonster(monster, chr, withDrops, second, animation, 0); } /** * 杀死怪物 * @param monster * @param chr * @param withDrops * @param second * @param animation * @param lastSkill */ public void killMonster(final MapleMonster monster, final MapleCharacter chr, boolean withDrops, boolean second, byte animation, int lastSkill) { // if (((monster.getId() == 8810122) || (monster.getId() == 8810018)) && (!second)) { // MapTimer.getInstance().schedule(new Runnable() { // @Override // public void run() { // MapleMap.this.killMonster(monster, chr, true, true, (byte) 1); // MapleMap.this.killAllMonsters(true); // } // }, 3000); // return; // } // if (monster.getStatusSourceID(MonsterStatus.持续掉血) == 2111010) { //TODO 处理绿水灵病毒 // Skill skills = SkillFactory.getSkill(2111010); // int skilllevel = chr.getSkillLevel(2111010); // MapleStatEffect infoEffect = skills.getEffect(skilllevel); // infoEffect.applyBuffEffect(chr, monster.getBuff(MonsterStatus.持续掉血).getPoisonSchedule()); // } 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 (dropOwner != -1) { // 这里加经验 monster.killGainExp(lastSkill); } int mobid = monster.getId(); ExpeditionType type = null; if ((mobid == 8800002) && ((this.mapid == 280030000))) { this.charactersLock.readLock().lock(); if (this.speedRunStart > 0L) { type = ExpeditionType.Zakum; } doShrine(true); } else if ((mobid >= 8800003) && (mobid <= 8800010)) { boolean makeZakReal = true; Collection<MapleMonster> monsters = getAllMonstersThreadsafe(); for (MapleMonster mons : monsters) { if ((mons.getId() >= 8800003) && (mons.getId() <= 8800010)) { makeZakReal = false; break; } } if (makeZakReal) { for (Object 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; Collection<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 >= 8800023 && mobid <= 8800030) { boolean makeZakReal = true; final Collection<MapleMonster> monsters = getAllMonstersThreadsafe(); for (final MapleMonster mons : monsters) { if (mons.getId() >= 8800023 && mons.getId() <= 8800030) { makeZakReal = false; break; } } if (makeZakReal) { for (final MapleMonster mons : monsters) { if (mons.getId() == 8800020) { final Point pos = mons.getTruePosition(); this.killAllMonsters(true); spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(8800020), pos); break; } } } } else if ((mobid >= 9400903) && (mobid <= 9400910)) { boolean makeZakReal = true; Collection<MapleMonster> monsters = getAllMonstersThreadsafe(); for (MapleMonster mons : monsters) { if ((mons.getId() >= 9400903) && (mons.getId() <= 9400910)) { makeZakReal = false; break; } } if (makeZakReal) { for (MapleMonster mons : monsters) { if (mons.getId() == 9400900) { Point pos = mons.getTruePosition(); killAllMonsters(true); spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(9400900), pos); break; } } } } else if ((mobid / 100000 == 98) && (chr.getMapId() / 10000000 == 95) && (getAllMonstersThreadsafe().isEmpty())) { switch (chr.getMapId() % 1000 / 100) { case 0: case 1: case 2: case 3: case 4: chr.getClient().getSession().write(UIPacket.MapEff("monsterPark/clear")); break; case 5: if (chr.getMapId() / 1000000 == 952) { chr.getClient().getSession().write(UIPacket.MapEff("monsterPark/clearF")); } else { chr.getClient().getSession().write(UIPacket.MapEff("monsterPark/clear")); } break; case 6: chr.getClient().getSession().write(UIPacket.MapEff("monsterPark/clearF")); } } else if ((mobid / 100000 == 93) && (chr.getMapId() / 1000000 == 955) && (getAllMonstersThreadsafe().isEmpty())) { switch (chr.getMapId() % 1000 / 100) { case 1: case 2: chr.getClient().getSession().write(MaplePacketCreator.showEffect("aswan/clear")); chr.getClient().getSession().write(MaplePacketCreator.playSound("Party1/Clear")); break; case 3: chr.getClient().getSession().write(MaplePacketCreator.showEffect("aswan/clearF")); chr.getClient().getSession().write(MaplePacketCreator.playSound("Party1/Clear")); chr.dropMessage(-1, "你已经通过了所有回合。请通过传送口移动到外部。"); } } if ((type != null) && (this.speedRunStart > 0L) && (this.speedRunLeader.length() > 0)) { String name = ""; switch (type.name()) { case "Normal_Balrog": name = "蝙蝠怪"; break; } long endTime = System.currentTimeMillis(); String time = StringUtil.getReadableMillis(this.speedRunStart, endTime); broadcastMessage(MaplePacketCreator.serverMessageNotice(new StringBuilder(127).append(this.speedRunLeader).append("带领的远征队,耗时: ").append(time).append(" 击败了 ").append(name).append("!").toString())); getRankAndAdd(this.speedRunLeader, time, type, endTime - this.speedRunStart, sqd == null ? null : sqd.getMembers()); endSpeedRun(); } if ((withDrops) && (dropOwner != -1)) { MapleCharacter drop; if (dropOwner <= 0) { drop = chr; } else { drop = getCharacterById(dropOwner); if (drop == null) { drop = chr; } } dropFromMonster(drop, monster, instanced); } if ((ServerConstants.打怪获得点抵用卷 || this.isBossMap()) && Randomizer.nextInt(100) < 30) { int NX = Math.max(monster.getMobLevel(), 1); if (chr.getParty() != null && chr.getParty().getMembers().size() >= 2) { for (MaplePartyCharacter pch : chr.getParty().getMembers()) { if (pch.getMapid() == this.getId()) { pch.getChr().modifyCSPoints(monster.getStats().isBoss() ? 1 : 2, NX / (7 - chr.getParty().getMembers().size()), true); } } } else { chr.modifyCSPoints(monster.getStats().isBoss() ? 1 : 2, NX / 10, true); } } else if (cangetNXMap() && Randomizer.nextInt(100) < 30) { int NX = Math.max(monster.getMobLevel(), 1); if (chr.getParty() != null && chr.getParty().getMembers().size() >= 1) { for (MaplePartyCharacter pch : chr.getParty().getMembers()) { if (pch.getMapid() == this.getId()) { pch.getChr().modifyCSPoints(monster.getStats().isBoss() ? 1 : 2, Math.max(NX / 150, 1) * chr.getParty().getMembers().size() * pch.getChr().getPQLog("MonsterPark"), true); } } } } } public boolean cangetNXMap() { switch (this.getId()) { case 952000000: return true; } if (this.getId() >= 952000000 && this.getId() <= 954061000 || this.getId() >= 925020100 && this.getId() <= 925033000) { return true; } return false; } public List<MapleReactor> getAllReactor() { return getAllReactorsThreadsafe(); } public List<MapleReactor> getAllReactorsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.REACTOR).values()) { ret.add((MapleReactor) mmo); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } return ret; } public List<MapleSummon> getAllSummonsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.SUMMON)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.SUMMON).values()) { if ((mmo instanceof MapleSummon)) { ret.add((MapleSummon) mmo); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.SUMMON)).readLock().unlock(); } return ret; } public List<MapleMapObject> getAllDoor() { return getAllDoorsThreadsafe(); } public List<MapleMapObject> getAllDoorsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.DOOR)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.DOOR).values()) { if ((mmo instanceof MapleDoor)) { ret.add(mmo); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.DOOR)).readLock().unlock(); } return ret; } public List<MapleMapObject> getAllMechDoorsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.DOOR)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.DOOR).values()) { if ((mmo instanceof MechDoor)) { ret.add(mmo); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.DOOR)).readLock().unlock(); } return ret; } public List<MapleMapObject> getAllMerchant() { return getAllHiredMerchantsThreadsafe(); } public List<MapleMapObject> getAllHiredMerchantsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.HIRED_MERCHANT)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.HIRED_MERCHANT).values()) { ret.add(mmo); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.HIRED_MERCHANT)).readLock().unlock(); } return ret; } public List<MapleMonster> getAllMonster() { return getAllMonstersThreadsafe(); } public List<MapleMonster> getAllMonstersThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.MONSTER).values()) { ret.add((MapleMonster) mmo); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().unlock(); } return ret; } public List<Integer> getAllUniqueMonsters() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.MONSTER).values()) { int theId = ((MapleMonster) mmo).getId(); if (!ret.contains(theId)) { ret.add(theId); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MONSTER)).readLock().unlock(); } return ret; } public void killAllMonsters(){ killAllMonsters(false); } public 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 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 void limitReactor(int rid, int num) { List<MapleReactor> toDestroy = new ArrayList(); Map 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(mr.getReactorId())) { if (((Integer) contained.get(mr.getReactorId())) >= num) { toDestroy.add(mr); } else { contained.put(mr.getReactorId(), ((Integer) contained.get(mr.getReactorId())) + 1); } } else { contained.put(mr.getReactorId(), 1); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } for (MapleReactor mr : toDestroy) { destroyReactor(mr.getObjectId()); } } public 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 void destroyReactor(int oid) { final MapleReactor reactor = getReactorByOid(oid); if (reactor == null) { return; } broadcastMessage(MaplePacketCreator.destroyReactor(reactor)); reactor.setAlive(false); removeMapObject(reactor); reactor.setTimerActive(false); if (reactor.getDelay() > 0) { MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { MapleMap.this.respawnReactor(reactor); } }, reactor.getDelay()); } } public 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(MaplePacketCreator.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 void resetReactors() { setReactorState((byte) 0); } public void setReactorState() { setReactorState((byte) 1); } public void setReactorState(byte state) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { ((MapleReactor) obj).forceHitReactor(state); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } } public void setReactorDelay(int state) { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject obj : mapobjects.get(MapleMapObjectType.REACTOR).values()) { ((MapleReactor) obj).setDelay(state); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } } public void shuffleReactors() { shuffleReactors(0, 9999999); } public 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 void updateMonsterController(MapleMonster monster) { if (!monster.isAlive() || (monster.getLinkCID() > 0) || (monster.getStats().isEscort())) { return; } MapleCharacter Controller = monster.getController(); if (Controller != null && Controller.getMap() != null) { if (Controller.getMap().getId() != this.getId() || Controller.getTruePosition().distance(monster.getTruePosition()) > monster.getRange()) { // FileoutputUtil.log("停止控制 " + monster.getObjectId() +" tr: "+Controller.getTruePosition().distance(monster.getTruePosition())+" "+monster.getRange()); monster.getController().stopControllingMonster(monster); } else { return; } } int mincontrolled = -1; MapleCharacter newController = null; this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if (!chr.isHidden() && (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) { // FileoutputUtil.log("新控制 " + monster.getObjectId()); if (monster.isFirstAttack()) { newController.controlMonster(monster, true); monster.setControllerHasAggro(true); } else { newController.controlMonster(monster, false); } } } public final MapleMapObject getMapObject(int oid, MapleMapObjectType type) { this.mapobjectlocks.get(type).readLock().lock(); try { return this.mapobjects.get(type).get(oid); } finally { this.mapobjectlocks.get(type).readLock().unlock(); } } public boolean containsNPC(int npcid) { 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 { this.mapobjectlocks.get(MapleMapObjectType.NPC).readLock().unlock(); } } public MapleNPC getNPCById(int id) { 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 { 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 MapleMonster getMonsterByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.MONSTER); if (mmo == null) { return null; } return (MapleMonster) mmo; } public MapleSummon getSummonByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.SUMMON); if (mmo == null) { return null; } return (MapleSummon) mmo; } public MapleNPC getNPCByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.NPC); if (mmo == null) { return null; } return (MapleNPC) mmo; } public MapleReactor getReactorByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.REACTOR); if (mmo == null) { return null; } return (MapleReactor) mmo; } public MonsterFamiliar getFamiliarByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.FAMILIAR); if (mmo == null) { return null; } return (MonsterFamiliar) mmo; } public MapleDefender getMistByOid(int oid) { MapleMapObject mmo = getMapObject(oid, MapleMapObjectType.MIST); if (mmo == null) { return null; } return (MapleDefender) mmo; } public 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)) { MapleReactor localMapleReactor1 = mr; return localMapleReactor1; } } return null; } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().unlock(); } } public 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(NPCPacket.spawnNPC(npc, true)); } public final void spawnNpcForPlayer(MapleClient c, final int id, final Point pos) { final 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); c.getSession().write(NPCPacket.spawnNPC(npc, true)); } public 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(NPCPacket.removeNPCController(npc.getObjectId())); broadcastMessage(NPCPacket.removeNPC(npc.getObjectId())); itr.remove(); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).writeLock().unlock(); } } public 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(NPCPacket.removeNPCController(npc.getObjectId())); broadcastMessage(NPCPacket.removeNPC(npc.getObjectId())); } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.NPC)).readLock().unlock(); } } public void spawnReactorOnGroundBelow(MapleReactor mob, Point pos) { mob.setPosition(pos); mob.setCustom(true); spawnReactor(mob); } public void spawnMonster_sSack(MapleMonster mob, Point pos, int spawnType) { mob.setPosition(calcPointBelow(new Point(pos.x, pos.y - 1))); spawnMonster(mob, spawnType); } public void spawnMonster_Pokemon(MapleMonster mob, Point pos, int spawnType) { Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); mob.setPosition(spos); spawnMonster(mob, spawnType, true); } public void spawnMonsterOnGroundBelow(MapleMonster mob, Point pos) { spawnMonster_sSack(mob, pos, -2); } public int spawnMonsterWithEffectBelow(MapleMonster mob, Point pos, int effect) { Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); return spawnMonsterWithEffect(mob, effect, spos); } public 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 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 spawnSimpleZakum(final int x, final int y) { final Point pos = new Point(x, y); final MapleMonster mainb = MapleLifeFactory.getMonster(8800020); final Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); mainb.setPosition(spos); mainb.setFake(true); // Might be possible to use the map object for reference in future. spawnFakeMonster(mainb); final int[] zakpart = {8800023, 8800024, 8800025, 8800026, 8800027, 8800028, 8800029, 8800030}; for (final int i : zakpart) { final MapleMonster part = MapleLifeFactory.getMonster(i); part.setPosition(spos); spawnMonster(part, -2); } if (squadSchedule != null) { cancelSquadSchedule(false); } } public void spawnPinkZakum(int x, int y) { Point pos = new Point(x, y); MapleMonster mainb = MapleLifeFactory.getMonster(9400900); Point spos = calcPointBelow(new Point(pos.x, pos.y - 1)); mainb.setPosition(spos); mainb.setFake(true); spawnFakeMonster(mainb); int[] zakpart = {9400903, 9400904, 9400905, 9400906, 9400907, 9400908, 9400909, 9400910}; for (int i : zakpart) { MapleMonster part = MapleLifeFactory.getMonster(i); part.setPosition(spos); spawnMonster(part, -2); } if (this.squadSchedule != null) { cancelSquadSchedule(false); } } public 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 void spawnRevives(final MapleMonster monster, final int oid) { monster.setMap(this); checkRemoveAfter(monster); monster.setLinkOid(oid); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public 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 void spawnMonster(MapleMonster monster, int spawnType) { spawnMonster(monster, spawnType, false); } public void spawnMonster(final MapleMonster monster, final int spawnType, final boolean overwrite) { monster.setMap(this); checkRemoveAfter(monster); if (monster.getId() == 9300166) { MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { broadcastMessage(MobPacket.killMonster(monster.getObjectId(), 2)); } }, 3000); } 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); spawnedMonstersOnMap.incrementAndGet(); } public int spawnMonsterWithEffect(final MapleMonster monster, final int effect, Point pos) { try { monster.setMap(this); monster.setPosition(pos); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() // spawnAndAddRangedMapObject(monster, new DelayedPacketCreation(monster, effect) { @Override public 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 void spawnFakeMonster(final MapleMonster monster) { monster.setMap(this); monster.setFake(true); spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { c.getSession().write(MobPacket.spawnMonster(monster, -4, 0)); } }); updateMonsterController(monster); this.spawnedMonstersOnMap.incrementAndGet(); } public void spawnReactor(final MapleReactor reactor) { reactor.setMap(this); spawnAndAddRangedMapObject(reactor, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { c.getSession().write(MaplePacketCreator.spawnReactor(reactor)); } }); } private void respawnReactor(MapleReactor reactor) { if ((!isSecretMap()) && (reactor.getReactorId() >= 100000) && (reactor.getReactorId() <= 200011)) { int newRid = (reactor.getReactorId() < 200000 ? 100000 : 200000) + Randomizer.nextInt(11); int prop = reactor.getReactorId() % 100; if ((Randomizer.nextInt(22) <= prop) && (newRid % 100 < 10)) { newRid++; } if ((Randomizer.nextInt(110) <= prop) && (newRid % 100 < 11)) { newRid++; } List toSpawnPos = new ArrayList(this.spawnPoints); for (MapleMapObject reactor1l : getAllReactorsThreadsafe()) { MapleReactor reactor2l = (MapleReactor) reactor1l; if ((!toSpawnPos.isEmpty()) && (toSpawnPos.contains(reactor2l.getPosition()))) { toSpawnPos.remove(reactor2l.getPosition()); } } MapleReactor newReactor = new MapleReactor(MapleReactorFactory.getReactor(newRid), newRid); newReactor.setPosition(toSpawnPos.isEmpty() ? reactor.getPosition() : (Point) toSpawnPos.get(Randomizer.nextInt(toSpawnPos.size()))); newReactor.setDelay(newRid % 100 == 11 ? 60000 : 5000); spawnReactor(newReactor); } else { reactor.setState((byte) 0); reactor.setAlive(true); spawnReactor(reactor); } } public boolean isSecretMap() { switch (this.mapid) { case 910001001: case 910001002: case 910001003: case 910001004: case 910001005: case 910001006: case 910001007: case 910001008: case 910001009: case 910001010: return true; } return false; } public final void spawnDoor(final MapleDoor door) { spawnAndAddRangedMapObject(door, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { door.sendSpawnData(c); c.getSession().write(MaplePacketCreator.enableActions()); } }); } public final void spawnArrowsTurret(final MapleArrowsTurret aturet) { //召唤箭矢炮盘 MapTimer tMan = MapTimer.getInstance(); final ScheduledFuture poisonSchedule; spawnAndAddRangedMapObject(aturet, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { broadcastMessage(SkillPacket.spawnArrowsTurret(aturet)); c.getSession().write(SkillPacket.ArrowsTurretAction(aturet)); } }); poisonSchedule = tMan.register(new Runnable() { @Override public void run() { //for (MapleCharacter chr : aturet.getMap().getCharacters()) { if (MapleMap.this.getCharacterById(aturet.getOwnerId()) == null) { //if (!aturet.getMap().getCharacters().equals(aturet.getOwner())) { MapleMap.this.removeMapObject(aturet); MapleMap.this.broadcastMessage(SkillPacket.cancelArrowsTurret(aturet)); } } }, 500, 500); aturet.setSchedule(tMan.schedule(new Runnable() { @Override public void run() { poisonSchedule.cancel(false); MapleMap.this.removeMapObject(aturet); MapleMap.this.broadcastMessage(SkillPacket.cancelArrowsTurret(aturet)); } }, ((20 + (long) Math.floor(aturet.getSkillLevel() / 3)) * 1000))); } 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(SummonPacket.spawnSummon(summon, true)); } } }); } public void spawnFamiliar(final MonsterFamiliar familiar) { spawnAndAddRangedMapObject(familiar, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { if ((familiar != null) && (c.getPlayer() != null)) { c.getSession().write(MaplePacketCreator.spawnFamiliar(familiar, true)); } } }); } public void spawnExtractor(final MapleExtractor ex) { spawnAndAddRangedMapObject(ex, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { ex.sendSpawnData(c); } }); } public void spawnLove(final MapleLove love) { spawnAndAddRangedMapObject(love, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { love.sendSpawnData(c); } }); MapTimer tMan = MapTimer.getInstance(); tMan.schedule(new Runnable() { @Override public void run() { MapleMap.this.broadcastMessage(MaplePacketCreator.removeLove(love.getObjectId(), love.getItemId())); MapleMap.this.removeMapObject(love); } }, 3600000L); } public void spawnMist(final MapleDefender mist, final int duration, boolean fake) { spawnAndAddRangedMapObject(mist, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { mist.sendSpawnData(c); } }); MapTimer tMan = MapTimer.getInstance(); final ScheduledFuture poisonSchedule; if ((mist.isPoisonMist()) && (!mist.isMobMist())) { final MapleCharacter owner = getCharacterById(mist.getOwnerId()); poisonSchedule = tMan.register(new Runnable() { @Override public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList(MapleMapObjectType.MONSTER))) { if ((mist.makeChanceResult()) && (!((MapleCharacter) mo).hasDOT()) && (((MapleCharacter) mo).getId() != mist.getOwnerId())) { ((MapleCharacter) mo).setDOT(mist.getSource().getDOT(), mist.getSourceSkill().getId(), mist.getSkillLevel()); } else if ((mist.makeChanceResult()) && (!((MapleMonster) mo).isBuffed(MonsterStatus.中毒)) && (owner != null)) { ((MapleMonster) mo).applyStatus(owner, new MonsterStatusEffect(MonsterStatus.中毒, 1, mist.getSourceSkill().getId(), null, false), true, duration, true, mist.getSource()); } } } }, 2000, 2500); } else {//poisonSchedule = tMan.register(new Runnable() //ScheduledFuture poisonSchedule; if (mist.isRecoverMist()) { poisonSchedule = tMan.register(new Runnable() { @Override public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList(MapleMapObjectType.PLAYER))) { MapleCharacter chr = (MapleCharacter) mo; if (mist.makeChanceResult() && chr.isAlive()) { chr.addMPHP((int) ((mist.getSource().getX() * (chr.getStat().getMaxHp() / 100.0D))), (int) (mist.getSource().getX() * (chr.getStat().getMaxMp() / 100.0D))); } } } }, 2000, 2500); } else if (!mist.isMobMist() && mist.getSourceSkill().getId() == 4121015) { final MapleCharacter owner = getCharacterById(mist.getOwnerId()); poisonSchedule = tMan.register(new Runnable() { @Override public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList( MapleMapObjectType.MONSTER))) { if ((mist.makeChanceResult()) && (!((MapleCharacter) mo).hasDOT()) && (((MapleCharacter) mo).getId() != mist.getOwnerId())) { ((MapleCharacter) mo).setDOT(mist.getSource().getDOT(), mist.getSourceSkill().getId(), mist.getSkillLevel()); } else if ((mist.makeChanceResult()) && (!((MapleMonster) mo).isBuffed(MonsterStatus.中毒)) && (owner != null)) { ((MapleMonster) mo).applyStatus(owner, new MonsterStatusEffect(MonsterStatus.物攻, -mist.getSource().getW(), mist.getSourceSkill().getId(), null, false), false, duration, true, mist.getSource()); ((MapleMonster) mo).applyStatus(owner, new MonsterStatusEffect(MonsterStatus.魔攻, -mist.getSource().getW(), mist.getSourceSkill().getId(), null, false), false, duration, true, mist.getSource()); ((MapleMonster) mo).applyStatus(owner, new MonsterStatusEffect(MonsterStatus.速度, mist.getSource().getY(), mist.getSourceSkill().getId(), null, false), false, duration, true, mist.getSource()); } } } }, 2000, 2500); } else if ((mist.isPoisonMist()) && (mist.isMobMist())) { poisonSchedule = tMan.register(new Runnable() { @Override public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList(MapleMapObjectType.PLAYER))) { ((MapleCharacter) mo).setDOT(mist.getSource().getDOT(), mist.getMobSkill().getSkillId(), mist.getMobSkill().getSkillLevel()); } } }, 2000, 2500); }else if ((mist.isGivebuff()) && (!mist.isMobMist())) { poisonSchedule = tMan.register(new Runnable() { @Override public void run() { for (MapleMapObject mo : MapleMap.this.getMapObjectsInRect(mist.getBox(), Collections.singletonList(MapleMapObjectType.PLAYER))) { if (((MapleCharacter) mo).getParty() != null && ((MapleCharacter) mo).getParty().getMemberById(mist.getOwnerId()) != null && ((MapleCharacter) mo).getBuffStats(mist.getSource(), -1) == null || ((MapleCharacter) mo).getId() == mist.getOwnerId() && ((MapleCharacter) mo).getBuffStats(mist.getSource(), -1) == null) { mist.getSource().applyBuffEffect(((MapleCharacter) mo), mist.getSource().getDuration()); } } if (MapleMap.this.getCharacterById_InMap(mist.getOwnerId()).getParty() != null && mist.getSourceSkill().getId() != 35121010) { for (MaplePartyCharacter mo : MapleMap.this.getCharacterById_InMap(mist.getOwnerId()).getParty().getMembers()) { if (!getCharactersIntersect(mist.getBox()).contains(MapleMap.this.getCharacterById_InMap(mo.getId())) && MapleMap.this.getCharacterById_InMap(mo.getId()).getBuffStats(mist.getSource(), -1) != null) { MapleMap.this.getCharacterById_InMap(mo.getId()).cancelEffect(mist.getSource(), false, -1); } } } } }, 2000, 2500); } else { int id = mist.isMobMist() ? mist.getMobSkill().getSkillId() : mist.getSourceSkill().getId(); String from = mist.isMobMist() ? "怪物" : "玩家:" + mist.getOwnerId(); FileoutputUtil.log("[未处理 mist] 来自 " + from + " 技能ID:" + id + ""); poisonSchedule = null; } } mist.setPoisonSchedule(poisonSchedule); mist.setSchedule(tMan.schedule(new Runnable() { @Override public void run() { MapleMap.this.removeMapObject(mist); if (poisonSchedule != null) { poisonSchedule.cancel(false); } MapleMap.this.broadcastMessage(MaplePacketCreator.removeMist(mist.getObjectId(), false)); } }, duration)); } public 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(InventoryPacket.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 3, false), drop.getTruePosition()); } public 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() { @Override public void sendPackets(MapleClient c) { c.getSession().write(InventoryPacket.dropItemFromMapObject(mdrop, dropper.getTruePosition(), droppos, (byte) 1, false)); } }); if (!this.everlast) { mdrop.registerExpire(120000L); if ((droptype == 0) || (droptype == 1)) { mdrop.registerFFA(30000L); } } } public 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() { @Override public void sendPackets(MapleClient c) { c.getSession().write(InventoryPacket.dropItemFromMapObject(mdrop, dropper.getTruePosition(), position, (byte) 1, false)); } }); mdrop.registerExpire(120000L); if ((droptype == 0) || (droptype == 1)) { mdrop.registerFFA(30000L); } } public 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() { @Override public void sendPackets(MapleClient c) { if ((c != null) && (c.getPlayer() != null) && ((questid <= 0) || (c.getPlayer().getQuestStatus(questid) == 1)) && ((idrop.getItemId() / 10000 != 238) ) && (mob != null) && (dropPos != null)) { c.getSession().write(InventoryPacket.dropItemFromMapObject(mdrop, mob.getTruePosition(), dropPos, (byte) 1, false)); } } }); mdrop.registerExpire(120000L); if ((droptype == 0) || (droptype == 1)) { mdrop.registerFFA(30000L); } activateItemReactors(mdrop, chr.getClient()); } public void spawnRandDrop() { if ((this.mapid != 910000000) || (this.channel != 1)) { return; } ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().lock(); try { for (MapleMapObject o : mapobjects.get(MapleMapObjectType.ITEM).values()) { if (((MapleMapItem) o).isRandDrop()) { return; } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().unlock(); } MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { Point pos = new Point(Randomizer.nextInt(800) + 531, -806); int theItem = Randomizer.nextInt(1000); int itemid; if (theItem < 950) { 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)]; } } MapleMap.this.spawnAutoDrop(itemid, pos); } }, 20000L); } public void spawnAutoDrop(int itemid, final Point pos) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); Item idrop; if (ItemConstants.getInventoryType(itemid) == MapleInventoryType.EQUIP) { idrop = ii.randomizeStats((Equip) ii.getEquipById(itemid)); } else { idrop = new Item(itemid, (byte) 0, (short) 1, (short) 0); } idrop.setGMLog(new StringBuilder().append("自动掉落 ").append(itemid).append(" 地图 ").append(this.mapid).toString()); final MapleMapItem mdrop = new MapleMapItem(pos, idrop); spawnAndAddRangedMapObject(mdrop, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { c.getSession().write(InventoryPacket.dropItemFromMapObject(mdrop, pos, pos, (byte) 1, false)); } }); broadcastMessage(InventoryPacket.dropItemFromMapObject(mdrop, pos, pos, (byte) 0, false)); if (itemid / 10000 != 291) { mdrop.registerExpire(120000L); } } public 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() { @Override public void sendPackets(MapleClient c) { c.getSession().write(InventoryPacket.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 1, false)); } }); broadcastMessage(InventoryPacket.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 0, false)); if (!this.everlast) { drop.registerExpire(120000L); activateItemReactors(drop, owner.getClient()); } } public void spawnItemDrop(final MapleMapObject dropper, MapleCharacter owner,int itemId,short quantity) { final Point droppos = calcDropPos(owner.getPosition(), owner.getPosition()); Item toDrop; MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); if (GameConstants.getInventoryType(itemId) == MapleInventoryType.EQUIP) { toDrop = ii.randomizeStats((Equip) ii.getEquipById(itemId)); } else { toDrop = new client.inventory.Item(itemId, (byte) 0, quantity, (byte) 0); } final MapleMapItem drop = new MapleMapItem(toDrop, droppos, dropper, owner, (byte) 2, false); spawnAndAddRangedMapObject(drop, new DelayedPacketCreation() { @Override public void sendPackets(MapleClient c) { c.getSession().write(InventoryPacket.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 1, false)); } }); broadcastMessage(InventoryPacket.dropItemFromMapObject(drop, dropper.getTruePosition(), droppos, (byte) 0, false)); if (!this.everlast) { drop.registerExpire(120000L); activateItemReactors(drop, owner.getClient()); } } private void activateItemReactors(MapleMapItem drop, MapleClient c) { Item item = drop.getItem(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.REACTOR)).readLock().lock(); try { for (MapleMapObject o : mapobjects.get(MapleMapObjectType.REACTOR).values()) { MapleReactor react = (MapleReactor) o; if ((react.getReactorType() == 100) && (item.getItemId() == GameConstants.getCustomReactItem(react.getReactorId(), (react.getReactItem().getLeft()))) && ((react.getReactItem().getRight()) == item.getQuantity()) && (react.getArea().contains(drop.getTruePosition())) && (!react.isTimerActive())) { MapTimer.getInstance().schedule(new ActivateItemReactor(drop, react, c), 5000L); react.setTimerActive(true); break; } } } finally { ((ReentrantReadWriteLock) this.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 int getRunesSize() { return ((LinkedHashMap) this.mapobjects.get(MapleMapObjectType.MAPLE_RUNE)).size(); } public List<MapleMapItem> getAllItems() { return getAllItemsThreadsafe(); } public List<MapleMapItem> getAllItemsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.ITEM).values()) { ret.add((MapleMapItem) mmo); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().unlock(); } return ret; } public Point getPointOfItem(int itemid) { ((ReentrantReadWriteLock) this.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)) { Point localPoint = mm.getPosition(); return localPoint; } } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().unlock(); } return null; } public List<MapleDefender> getAllMistsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MIST)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.MIST).values()) { ret.add((MapleDefender) mmo); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.MIST)).readLock().unlock(); } return ret; } public void returnEverLastItem(MapleCharacter chr) { for (MapleMapObject o : getAllItemsThreadsafe()) { MapleMapItem item = (MapleMapItem) o; if (item.getOwner() == chr.getId()) { item.setPickedUp(true); broadcastMessage(InventoryPacket.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 void startMapEffect(String msg, int itemId) { startMapEffect(msg, itemId, false); } public 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()); MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { if (MapleMap.this.mapEffect != null) { MapleMap.this.broadcastMessage(MapleMap.this.mapEffect.makeDestroyData()); MapleMap.this.mapEffect = null; } } }, jukebox ? 300000L : 30000L); } public void startPredictCardMapEffect(String msg, int itemId, int effectType) { startMapEffect(msg, itemId, 30, effectType); } public void startMapEffect(String msg, int itemId, int time) { startMapEffect(msg, itemId, time, -1); } public void startMapEffect(String msg, int itemId, int time, int effectType) { if (this.mapEffect != null) { return; } if (time <= 0) { time = 5; } this.mapEffect = new MapleMapEffect(msg, itemId, effectType); this.mapEffect.setJukebox(false); // broadcastMessage(this.mapEffect.makeStartData()); MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { if (MapleMap.this.mapEffect != null) { MapleMap.this.broadcastMessage(MapleMap.this.mapEffect.makeDestroyData()); MapleMap.this.mapEffect = null; } } }, time * 1000); } public void startExtendedMapEffect(final String msg, final int itemId) { broadcastMessage(MaplePacketCreator.startMapEffect(msg, itemId, true)); MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { MapleMap.this.broadcastMessage(MaplePacketCreator.removeMapEffect()); MapleMap.this.broadcastMessage(MaplePacketCreator.startMapEffect(msg, itemId, false)); } }, 60000L); } public void startSimpleMapEffect(String msg, int itemId) { broadcastMessage(MaplePacketCreator.startMapEffect(msg, itemId, true)); } public void startJukebox(String msg, int itemId) { startMapEffect(msg, itemId, true); } /** * 添加玩家到地图 * * @param chr */ public final void addPlayer(final MapleCharacter chr) { this.mapobjectlocks.get(MapleMapObjectType.PLAYER).writeLock().lock(); try { this.mapobjects.get(MapleMapObjectType.PLAYER).put(chr.getObjectId(), chr); } finally { this.mapobjectlocks.get(MapleMapObjectType.PLAYER).writeLock().unlock(); } this.charactersLock.writeLock().lock(); try { this.characters.add(chr); } finally { this.charactersLock.writeLock().unlock(); } chr.setChangeTime(true); if ((GameConstants.isTeamMap(this.mapid))) { chr.setTeam(getAndSwitchTeam() ? 0 : 1); } byte[] packet = MaplePacketCreator.spawnPlayerMapobject(chr); //封包在这 if (!chr.isHidden()) { broadcastMessage(chr, packet, false); if ((chr.isIntern()) && (this.speedRunStart > 0L)) { endSpeedRun(); broadcastMessage(MaplePacketCreator.serverMessageNotice("The speed run has ended.")); } } else { broadcastGMMessage(chr, packet, false); } if (!onFirstUserEnter.equals("")) { if (getCharactersSize() == 1) { MapScriptMethods.startScript_FirstUser(chr.getClient(), onFirstUserEnter); } } if (!onUserEnter.equals("")) { MapScriptMethods.startScript_User(chr.getClient(), onUserEnter); } sendObjectPlacement(chr); // GameConstants.achievementRatio(chr.getClient()); if ((GameConstants.isTeamMap(this.mapid)) ) { //chr.getClient().getSession().write(MaplePacketCreator.showEquipEffect(chr.getTeam())); } MaplePet pets = chr.getSpawnPets(); //宠物发的包 if ((pets != null) && (pets.getSummoned())) { pets.setPos(chr.getTruePosition()); // chr.getClient().getSession().write(PetPacket.updatePet(pets, chr.getInventory(MapleInventoryType.CASH).getItem((short) (byte) pets.getInventoryPosition()), false)); chr.getClient().getSession().write(PetPacket.showPet(chr, pets, false, false, true)); // chr.getClient().getSession().write(PetPacket.loadExceptionList(chr, pets)); } if (chr.getSummonedFamiliar() != null) { // chr.spawnFamiliar(chr.getSummonedFamiliar()); } if (chr.getParty() != null) { // chr.silentPartyUpdate(); // chr.getClient().getSession().write(PartyPacket.updateParty(chr.getClient().getChannel(), chr.getParty(), PartyOperation.更新队伍, null)); // chr.updatePartyMemberHP(); // chr.receivePartyMemberHP(); } boolean quickMove = false; if ((!chr.isInBlockedMap()) && (chr.getLevel() >= 10)) { for (MapleQuickMove qm : MapleQuickMove.values()) { if (qm.getMap() == chr.getMapId()) { List<MapleQuickMove.QuickMoveNPC> qmn = new LinkedList(); int npcs = qm.getNPCFlag(); for (MapleQuickMove.QuickMoveNPC npc : MapleQuickMove.QuickMoveNPC.values()) { if ((npcs & npc.getValue()) != 0 && npc.show()) { qmn.add(npc); } } quickMove = true; chr.getClient().getSession().write(MaplePacketCreator.getQuickMoveInfo(true, qmn)); break; } } } if (!quickMove) { // chr.getClient().getSession().write(MaplePacketCreator.getQuickMoveInfo(false, new LinkedList())); } Map<Integer,MapleSummon> ss = chr.getSummonsReadLock();//召唤兽 try { for (MapleSummon summon : ss.values()) { summon.setPosition(chr.getTruePosition()); chr.addVisibleMapObject(summon); spawnSummon(summon); } } finally { chr.unlockSummonsReadLock(); } // if (this.mapEffect != null) { // this.mapEffect.sendStartData(chr.getClient()); // } if ((this.timeLimit > 0) && (getForcedReturnMap() != null)) { chr.startMapTimeLimitTask(this.timeLimit, getForcedReturnMap()); } // if ((chr.getBuffedValue(MapleBuffStat.骑兽技能) != null) && (!GameConstants.is反抗者(chr.getJob())) // && (FieldLimitType.Mount.check(this.fieldLimit))) { // chr.cancelEffectFromBuffStat(MapleBuffStat.骑兽技能); // } if (chr.getSidekick() != null) { MapleCharacter side = getCharacterById(chr.getSidekick().getCharacter(chr.getSidekick().getCharacter(0).getId() == chr.getId() ? 1 : 0).getId()); if (side != null) { chr.getSidekick().applyBuff(side); chr.getSidekick().applyBuff(chr); } } if ((chr.getEventInstance() != null) && (chr.getEventInstance().isTimerStarted())) { chr.getClient().getSession().write(MaplePacketCreator.getClock((int) (chr.getEventInstance().getTimeLeft() / 1000L))); } if (hasClock()) { Calendar cal = Calendar.getInstance(); chr.getClient().getSession().write(MaplePacketCreator.getClockTime(cal.get(11), cal.get(12), cal.get(13))); } if(hasBoat() == 2) { // 船还在 chr.getClient().getSession().write(MaplePacketCreator.boatPacket(true)); } if ((chr.getCarnivalParty() != null) && (chr.getEventInstance() != null)) { chr.getEventInstance().onMapLoad(chr); } MapleEvent.mapLoad(chr, this.channel); if ((getSquadBegin() != null) && (getSquadBegin().getTimeLeft() > 0L) && (getSquadBegin().getStatus() == 1)) { chr.getClient().getSession().write(MaplePacketCreator.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 == 280030100) || (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: case 280030100: music = "Bgm06/FinalFight"; } chr.getClient().getSession().write(MaplePacketCreator.musicChange(music)); } if (this.permanentWeather > 0) { chr.getClient().getSession().write(MaplePacketCreator.startMapEffect("", this.permanentWeather, false)); } if (getPlatforms().size() > 0) { chr.getClient().getSession().write(MaplePacketCreator.getMovingPlatforms(this)); } if (this.environment.size() > 0) { chr.getClient().getSession().write(MaplePacketCreator.getUpdateEnvironment(this)); } } public int getNumItems() { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().lock(); try { return mapobjects.get(MapleMapObjectType.ITEM).size(); } finally { mapobjectlocks.get(MapleMapObjectType.ITEM).readLock().unlock(); } } public int getNumMonsters() { mapobjectlocks.get(MapleMapObjectType.MONSTER).readLock().lock(); try { return mapobjects.get(MapleMapObjectType.MONSTER).size(); } finally { 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) || (this.mapid == 280030100) ? 1 : 0; EventManager em = getEMByMap(); if ((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) { //chaoszakum broadcastMessage(MaplePacketCreator.showChaosZakumShrine(spawned, 5)); } else if (mode == 3) { //ht/chaosht broadcastMessage(MaplePacketCreator.showChaosHorntailShrine(spawned, 5)); } else { broadcastMessage(MaplePacketCreator.showHorntailShrine(spawned, 5)); } if (spawned) { //both of these together dont go well broadcastMessage(MaplePacketCreator.getClock(300)); } final MapleMap returnMapz = returnMapa; Runnable run; if (!spawned) { final List<MapleMonster> monsterz = getAllMonstersThreadsafe(); final List<Integer> monsteridz = new ArrayList<>(); for (MapleMapObject m : monsterz) { monsteridz.add(m.getObjectId()); } run = new Runnable() { @Override 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 (int i : monsteridz) { if (m.getObjectId() == i) { passed = true; break; } } if (passed) { break; } } if (passed) { byte[] packet; if ((mode == 1) || (mode == 2)) { packet = MaplePacketCreator.showChaosZakumShrine(spawned, 0); } else { packet = MaplePacketCreator.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() { @Override 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 = MaplePacketCreator.showChaosZakumShrine(spawned, 0); } else { packet = MaplePacketCreator.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 = MapTimer.getInstance().schedule(run, 300000L); } } public MapleSquad getSquadByMap() { MapleSquadType zz; switch (this.mapid) { case 105100300: case 105100400: zz = MapleSquadType.bossbalrog; break; case 280030000: case 280030100: 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 270051100: zz = MapleSquadType.chaospb; 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; case 689013000: zz = MapleSquadType.pinkzak; break; case 262030300: case 262031300: case 262031310: zz = MapleSquadType.hillah; break; case 272030400: case 272030420: zz = MapleSquadType.arkarium; break; default: return null; } return ChannelServer.getInstance(this.channel).getMapleSquad(zz); } public MapleSquad getSquadBegin() { if (this.squad != null) { return ChannelServer.getInstance(this.channel).getMapleSquad(this.squad); } return null; } public EventManager getEMByMap() { String em; switch (this.mapid) { case 105100400: em = "BossBalrog_EASY"; break; case 105100300: em = "BossBalrog_NORMAL"; break; case 280030000: case 280030100: em = "ZakumBattle"; break; case 240060200: em = "HorntailBattle"; break; case 280030001: em = "ChaosZakum"; break; case 240060201: em = "ChaosHorntail"; break; case 270050100: em = "PinkBeanBattle"; break; case 270051100: em = "ChaosPinkBean"; 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 689013000: em = "PinkZakum"; break; case 262031300: case 262031310: em = "Hillah_170"; break; case 272030400: case 272030420: em = "ArkariumBattle"; break; case 955000100: case 955000200: case 955000300: em = "AswanOffSeason"; break; default: if (mapid >= 262020000 && mapid < 262023000) { em = "Azwan"; break; } return null; } return ChannelServer.getInstance(this.channel).getEventSM().getEventManager(em); } /** * 移除玩家离开地图 * @param chr */ public void removePlayer(MapleCharacter chr) { if (this.everlast) { returnEverLastItem(chr); } this.charactersLock.writeLock().lock(); try { this.characters.remove(chr); } finally { this.charactersLock.writeLock().unlock(); } removeMapObject(chr); chr.removeExtractor(); if (chr.getSidekick() != null) { MapleCharacter side = getCharacterById(chr.getSidekick().getCharacter(chr.getSidekick().getCharacter(0).getId() == chr.getId() ? 1 : 0).getId()); } broadcastMessage(MaplePacketCreator.removePlayerFromMap(chr.getId())); if (chr.getSummonedFamiliar() != null) { chr.removeVisibleFamiliar(); } List<MapleSummon> toCancel = new ArrayList(); Map<Integer,MapleSummon> listSummons = chr.getSummonsReadLock(); try { for (MapleSummon summon : listSummons.values()) { broadcastMessage(SummonPacket.removeSummon(summon, true)); removeMapObject(summon); // 不能移动的召唤物,换地图后就没有了 if ((summon.getMovementType() == SummonMovementType.不会移动) || (summon.getMovementType() == SummonMovementType.CIRCLE_STATIONARY) || (summon.getMovementType() == SummonMovementType.自由移动)) { ((List) toCancel).add(summon); } else { summon.setChangedMap(true); } } } finally { chr.unlockSummonsReadLock(); } // @TODO 这里应该可以合并到上面去的 for (MapleSummon summon : toCancel) { chr.removeSummon(summon.getSkillId()); chr.dispelSkill(summon.getSkillId()); } checkStates(chr.getName()); if (this.mapid == 109020001) { chr.canTalk(true); } chr.leaveMap(this); } public void broadcastMessage(byte[] packet) { broadcastMessage(null, packet, Double.POSITIVE_INFINITY, null); } public void broadcastMessage(MapleCharacter source, byte[] packet, boolean repeatToSource) { broadcastMessage(repeatToSource ? null : source, packet, Double.POSITIVE_INFINITY, source.getTruePosition()); } public void broadcastMessage(byte[] packet, Point rangedFrom) { broadcastMessage(null, packet, GameConstants.maxViewRangeSq(), rangedFrom); } public 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 : characters) { if (chr != source) { if (rangeSq < Double.POSITIVE_INFINITY) { if (rangedFrom.distance(chr.getTruePosition()) <= rangeSq) { chr.getClient().getSession().write(packet); } } else { chr.getClient().getSession().write(packet); } } } } finally { this.charactersLock.readLock().unlock(); } } private void sendObjectPlacement(MapleCharacter chr) { //标记载入地图所有存在的实例 召唤兽第一次载入的包 if (chr == null) { return; } for (MapleMapObject o : getMapObjectsInRange(chr.getTruePosition(), chr.getRange(), GameConstants.rangedMapobjectTypes)) { if ((o.getType() == MapleMapObjectType.REACTOR) && (!((MapleReactor) o).isAlive())) { continue; } o.sendSpawnData(chr.getClient()); chr.addVisibleMapObject(o); } } public 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 List<MapleMapObject> getMapObjectsInRange(Point from, double rangeSq) { List ret = new ArrayList(); for (MapleMapObjectType type : MapleMapObjectType.values()) { mapobjectlocks.get(type).readLock().lock(); try { Iterator<MapleMapObject> itr = mapobjects.get(type).values().iterator(); while (itr.hasNext()) { MapleMapObject mmo = (MapleMapObject) itr.next(); if (from.distanceSq(mmo.getTruePosition()) <= rangeSq) { ret.add(mmo); } } } finally { 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 List<MapleMapObject> getMonstersInRange(Point from, double rangeSq) { return getMapObjectsInRange(from, rangeSq, Arrays.asList(new MapleMapObjectType[]{MapleMapObjectType.MONSTER})); } public List<MapleMapObject> getMapObjectsInRange(Point from, double rangeSq, List<MapleMapObjectType> MapObject_types) { List ret = new ArrayList(); for (MapleMapObjectType type : MapObject_types) { 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 { mapobjectlocks.get(type).readLock().unlock(); } } return ret; } /** * 获取矩形中的怪物信息 * @param box * @param MapObject_types * @return */ public List<MapleMapObject> getMapObjectsInRect(Rectangle box, List<MapleMapObjectType> MapObject_types) { List ret = new ArrayList(); for (MapleMapObjectType type : MapObject_types) { 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 { mapobjectlocks.get(type).readLock().unlock(); } } return ret; } public 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 List<MapleCharacter> getPlayersInRectAndInList(Rectangle box, List<MapleCharacter> chrList) { List character = new LinkedList(); this.charactersLock.readLock().lock(); try { for (MapleCharacter a : this.characters) { if ((chrList.contains(a)) && (box.contains(a.getTruePosition()))) { character.add(a); } } } finally { this.charactersLock.readLock().unlock(); } return character; } public void addPortal(MaplePortal myPortal) { this.portals.put(myPortal.getId(), myPortal); } public MaplePortal getPortal(String portalname) { for (MaplePortal port : this.portals.values()) { if (port.getName().equals(portalname)) { return port; } } return null; } public MaplePortal getPortal(int portalid) { return (MaplePortal) this.portals.get(portalid); } public void resetPortals() { for (MaplePortal port : this.portals.values()) { port.setPortalState(true); } } public void setFootholds(MapleFootholdTree footholds) { this.footholds = footholds; } public MapleFootholdTree getFootholds() { return this.footholds; } public int getNumSpawnPoints() { return this.monsterSpawn.size(); } public void loadMonsterRate(boolean first) { int spawnSize = this.monsterSpawn.size(); if ((spawnSize >= 20) || (this.partyBonusRate > 0)) { this.maxRegularSpawn = Math.round(spawnSize / this.monsterRate); } else { this.maxRegularSpawn = (int) Math.ceil(spawnSize * this.monsterRate); } if (this.fixedMob > 0) { this.maxRegularSpawn = this.fixedMob; } else if (this.maxRegularSpawn <= 2) { this.maxRegularSpawn = 2; } else if (this.maxRegularSpawn > spawnSize) { this.maxRegularSpawn = Math.max(10, spawnSize); } Collection newSpawn = new LinkedList(); Collection newBossSpawn = new LinkedList(); for (Spawns s : this.monsterSpawn) { if (s.getCarnivalTeam() >= 2) { continue; } if (s.getMonster().isBoss()) { newBossSpawn.add(s); } else { newSpawn.add(s); } } this.monsterSpawn.clear(); this.monsterSpawn.addAll(newBossSpawn); this.monsterSpawn.addAll(newSpawn); if ((first) && (spawnSize > 0)) { this.lastSpawnTime = System.currentTimeMillis(); if (GameConstants.isForceRespawn(this.mapid)) { this.createMobInterval = 15000; } respawn(false); // this should do the trick, we don't need to wait upon entering map } } public 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 void addAreaMonsterSpawn(MapleMonster monster, Point pos1, Point pos2, Point pos3, int mobTime, String msg, boolean shouldSpawn, boolean sendWorldMsg) { 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)) { FileoutputUtil.log(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, sendWorldMsg)); } public List<MapleCharacter> getCharacters() { return getCharactersThreadsafe(); } public 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 MapleCharacter getCharacterByName(String id) { this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { if (mc.getName().equalsIgnoreCase(id)) { MapleCharacter localMapleCharacter1 = mc; return localMapleCharacter1; } } } finally { this.charactersLock.readLock().unlock(); } return null; } public MapleCharacter getCharacterById_InMap(int id) { return getCharacterById(id); } public MapleCharacter getCharacterById(int id) { this.charactersLock.readLock().lock(); try { for (MapleCharacter mc : this.characters) { if (mc.getId() == id) { MapleCharacter localMapleCharacter1 = mc; return localMapleCharacter1; } } } finally { this.charactersLock.readLock().unlock(); } return null; } public void updateMapObjectVisibility(MapleCharacter chr, MapleMapObject mo) { if (chr == null) { 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().distance(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().distance(chr.getTruePosition()) > mo.getRange())) { chr.removeVisibleMapObject(mo); mo.sendDestroyData(chr.getClient()); } else if ((mo.getType() == MapleMapObjectType.MONSTER) && (chr.getTruePosition().distance(mo.getTruePosition()) <= mo.getRange())) { 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); Collection<MapleMapObject> visibleObjects; try { 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) { player.removeVisibleMapObject(mo); } } for (MapleMapObject mo : getMapObjectsInRange(player.getTruePosition(), player.getRange())) { if ((mo != null) && (!visibleObjects.contains(mo))) { mo.sendSpawnData(player.getClient()); player.addVisibleMapObject(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 = Double.POSITIVE_INFINITY; 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 getMapObjectSize() { return this.mapobjects.size(); } public int getCharactersSize() { this.charactersLock.readLock().lock(); try { int i = this.characters.size(); return i; } finally { this.charactersLock.readLock().unlock(); } } public Collection<MaplePortal> getPortals() { return Collections.unmodifiableCollection(this.portals.values()); } public int getSpawnedMonstersOnMap() { return this.spawnedMonstersOnMap.get(); } public void respawn(boolean force) { respawn(force, System.currentTimeMillis()); } public void respawn(boolean force, long now) { 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 (!isSpawns && (spawnPoint.getMobTime() > 0)) { continue; } if ((spawnPoint.shouldSpawn(lastSpawnTime)) || (GameConstants.isForceRespawn(mapid)) || (monsterSpawn.size() < 10 && this.maxRegularSpawn > 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(id); } public void addDisconnected(int id) { this.dced.add(id); } public void resetDisconnected() { this.dced.clear(); } public void startSpeedRun() { MapleSquad squads = getSquadByMap(); if (squads != null) { this.charactersLock.readLock().lock(); try { for (MapleCharacter chr : this.characters) { if ((chr.getName().equals(squads.getLeaderName())) && (!chr.isIntern())) { startSpeedRun(chr.getName()); return; } } } finally { this.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 getRankAndAdd(String leader, String time, ExpeditionType type, long timz, Collection<String> squad) { try { long lastTime = SpeedRunner.getSpeedRunData(type) == null ? 0L : (SpeedRunner.getSpeedRunData(type).right); 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(); try (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 (SQLException e) { e.printStackTrace(); } } public long getSpeedRunStart() { return this.speedRunStart; } public 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 ret = new ArrayList(); 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 List<MapleArrowsTurret> getAllArrowsTurrets() { return getArrowsTurretsThreadsafe(); } public List<MapleArrowsTurret> getArrowsTurretsThreadsafe() { ArrayList ret = new ArrayList(); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ARROWS_TURRET)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.ARROWS_TURRET).values()) { ret.add((MapleArrowsTurret) mmo); } } finally { ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ARROWS_TURRET)).readLock().unlock(); } return ret; } public void resetNPCs() { removeNpc(-1); } public void resetPQ(int level) { resetFully(); for (MapleMonster mons : getAllMonstersThreadsafe()) { mons.getStats().setChange(true); mons.changeLevel(level, true); } resetSpawnLevel(level); } public void resetSpawnLevel(int level) { for (Spawns spawn : this.monsterSpawn) { if ((spawn instanceof SpawnPoint)) { ((SpawnPoint) spawn).setLevel(level); } } } public void resetFully() { resetFully(true); } public void resetFully(boolean respawn) { killAllMonsters(false); reloadReactors(); removeDrops(); resetNPCs(); resetSpawns(); resetDisconnected(); endSpeedRun(); cancelSquadSchedule(true); resetPortals(); this.environment.clear(); if (respawn) { respawn(true); } } public void cancelSquadSchedule(boolean interrupt) { this.squadTimer = false; this.checkStates = true; if (this.squadSchedule != null) { this.squadSchedule.cancel(interrupt); this.squadSchedule = null; } } public void removeDrops() { List<MapleMapItem> mapItems = getAllItemsThreadsafe(); for (MapleMapItem mapItem : mapItems) { mapItem.expire(this); } } public void removeDropsDelay() { List<MapleMapItem> mapItems = getAllItemsThreadsafe(); int delay = 0; int i = 0; for (MapleMapItem mapItem : mapItems) { i++; if (i < 50) { mapItem.expire(this); } else { delay++; if (mapItem.hasFFA()) { mapItem.registerFFA(delay * 20); } else { mapItem.registerExpire(delay * 30); } } } } public void resetAllSpawnPoint(int mobid, int mobTime) { Collection<Spawns> AllSpawnPoints = new LinkedList(this.monsterSpawn); resetFully(); this.monsterSpawn.clear(); for (Spawns spawnPoint : AllSpawnPoints) { MapleMonster newMons = MapleLifeFactory.getMonster(mobid); newMons.setF(spawnPoint.getF()); newMons.setFh(spawnPoint.getFh()); newMons.setPosition(spawnPoint.getPosition()); addMonsterSpawn(newMons, mobTime, (byte) -1, null); } loadMonsterRate(true); } public void resetSpawns() { boolean changed = false; Iterator AllSpawnPoints = this.monsterSpawn.iterator(); while (AllSpawnPoints.hasNext()) { if (((Spawns) AllSpawnPoints.next()).getCarnivalId() > -1) { AllSpawnPoints.remove(); changed = true; } } setSpawns(true); if (changed) { loadMonsterRate(true); } } public 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 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) == team) || (((Integer) guard.right) == -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 void blockAllPortal() { for (MaplePortal p : this.portals.values()) { p.setPortalState(false); } } public boolean getAndSwitchTeam() { return getCharactersSize() % 2 != 0; } public void setSquad(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 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 List<Rectangle> getAreas() { return this.nodes.getAreas(); } public Rectangle getArea(int index) { return this.nodes.getArea(index); } public void changeEnvironment(String ms, int type) { broadcastMessage(MaplePacketCreator.environmentChange(ms, type)); } public void toggleEnvironment(String ms) { if (this.environment.containsKey(ms)) { moveEnvironment(ms, (this.environment.get(ms)) == 1 ? 2 : 1); } else { moveEnvironment(ms, 1); } } public void moveEnvironment(String ms, int type) { broadcastMessage(MaplePacketCreator.environmentMove(ms, type)); this.environment.put(ms, type); } public Map<String, Integer> getEnvironment() { return this.environment; } public int getNumPlayersInArea(int index) { return getNumPlayersInRect(getArea(index)); } public 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 int getNumPlayersItemsInArea(int index) { return getNumPlayersItemsInRect(getArea(index)); } public int getNumPlayersItemsInRect(Rectangle rect) { int ret = getNumPlayersInRect(rect); ((ReentrantReadWriteLock) this.mapobjectlocks.get(MapleMapObjectType.ITEM)).readLock().lock(); try { for (MapleMapObject mmo : mapobjects.get(MapleMapObjectType.ITEM).values()) { if (rect.contains(mmo.getTruePosition())) { ret++; } } } finally { ((ReentrantReadWriteLock) this.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 void broadcastNONGMMessage(MapleCharacter source, byte[] packet, boolean repeatToSource) { broadcastNONGMMessage(repeatToSource ? null : source, packet); } private void broadcastNONGMMessage(MapleCharacter source, byte[] packet) { charactersLock.readLock().lock(); try { if (source == null) { for (MapleCharacter chr : characters) { if (!chr.isStaff()) { chr.getClient().getSession().write(packet); } } } else { for (MapleCharacter chr : characters) { if (chr != source && (chr.getGMLevel() < source.getGMLevel())) { chr.getClient().getSession().write(packet); } } } } finally { charactersLock.readLock().unlock(); } } public List<Pair<Integer, Integer>> getMobsToSpawn() { return this.nodes.getMobsToSpawn(); } public List<Integer> getSkillIds() { return this.nodes.getSkillIds(); } public boolean canSpawn(long now) { return (this.lastSpawnTime > 0L) && (this.lastSpawnTime + this.createMobInterval < now); } public boolean canHurt(long now) { if ((this.lastHurtTime > 0L) && (this.lastHurtTime + this.decHPInterval < now)) { this.lastHurtTime = now; return true; } return false; } public void resetShammos(final MapleClient c) { killAllMonsters(true); broadcastMessage(MaplePacketCreator.serverMessageNotice("A player has moved too far from Shammos. Shammos is going back to the start.")); EtcTimer.getInstance().schedule(new Runnable() { @Override 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 List<Pair<Point, Integer>> getGuardians() { return this.nodes.getGuardians(); } public MapleNodes.DirectionInfo getDirectionInfo(int i) { return this.nodes.getDirection(i); } public void AutoNx(int jsNx, boolean isAutoPoints) { if (this.mapid != 910000000) { return; } for (MapleCharacter chr : this.characters) { if (chr != null) { if (isAutoPoints) { chr.gainPlayerPoints(10); chr.dropMessage(5, "[系统奖励] 在线时间奖励获得 [10] 点积分."); } else { int givNx = chr.getLevel() / 10 + jsNx; chr.modifyCSPoints(2, givNx); chr.dropMessage(5, new StringBuilder().append("[系统奖励] 在线时间奖励获得 [").append(givNx).append("] 点抵用券.").toString()); } } } } public void AutoGain(int rate, int expRate) { for (MapleCharacter chr : this.characters) { if (chr == null) { return; } int giveP; if (Randomizer.isSuccess(40)) { giveP = Randomizer.rand(4, 5) * 3; } else { giveP = Randomizer.rand(2, 3) * 3; } giveP *= rate; chr.modifyCSPoints(2, giveP); String msg = "在线奖励 [" + giveP + "] 抵用券"; if (chr.getLevel() < 255) { int givExp = chr.getLevel() <= 10 ? chr.getLevel() ^ 5 : chr.getLevel() * expRate * Randomizer.rand(8, 12); givExp *= rate; chr.gainExp(givExp, true, false, true); msg += "和 [" + givExp + "] 经验"; } if (rate > 1) { msg += " (" + rate + "倍)"; } chr.dropMessage(-5, msg); } } public boolean isMarketMap() { return (this.mapid >= 910000000) && (this.mapid <= 910000017); } public boolean isBossMap() { switch (this.mapid) { case 105100300: case 105100400: case 211070100: case 211070101: case 211070110: case 220080001: case 240040700: case 240060200: case 240060201: case 262031300: case 262031310: case 270050100: case 271040100: case 271040200: case 272030400: case 272030420: case 280030000: case 280030001: case 280030100: case 300030310: case 551030200: case 802000111: case 802000211: case 802000311: case 802000411: case 802000611: case 802000711: case 802000801: case 802000802: case 802000803: case 802000821: case 802000823: return true; } return false; } private int hasBoat() { return docked ? 2 : (boat ? 1 : 0); } public void setBoat(boolean hasBoat) { this.boat = hasBoat; } /** * 设置是否可以停靠船只 * @param isDocked */ public void setDocked(boolean isDocked) { this.docked = isDocked; } public void checkMoveMonster(Point from, boolean fly, MapleCharacter chr) { if ((this.maxRegularSpawn <= 2) || (this.monsterSpawn.isEmpty()) || (this.monsterRate <= 1.0D) || (chr == null)) { return; } //检测吸怪 /*int check = (int) ((fly ? 70 : 60) / 100.0D * this.maxRegularSpawn); if (getMonstersInRange(from, 5000.0D).size() >= check) { for (MapleMapObject obj : getMonstersInRange(from, (1.0D / 0.0D))) { MapleMonster mob = (MapleMonster) obj; killMonster(mob, chr, false, false, (byte) 1); } }*/ } private static abstract interface DelayedPacketCreation { public abstract void sendPackets(MapleClient paramMapleClient); } private class ActivateItemReactor implements Runnable { private final MapleMapItem mapitem; private final MapleReactor reactor; private final MapleClient c; public ActivateItemReactor(MapleMapItem mapitem, MapleReactor reactor, MapleClient c) { this.mapitem = mapitem; this.reactor = reactor; this.c = c; } @Override 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) { MapTimer.getInstance().schedule(new Runnable() { @Override public void run() { MapleMap.ActivateItemReactor.this.reactor.forceHitReactor((byte) 0); } }, this.reactor.getDelay()); } } else { this.reactor.setTimerActive(false); } } } }