package handling.channel.handler; import client.MapleCharacter; import client.MapleCharacterUtil; import client.MapleClient; import client.MonsterFamiliar; import client.SkillFactory; import client.inventory.Item; import client.inventory.MapleInventoryType; import client.status.MonsterStatus; import client.status.MonsterStatusEffect; import constants.GameConstants; import java.awt.Point; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import server.MapleInventoryManipulator; import server.MapleItemInformationProvider; import server.Randomizer; import server.StructFamiliar; import server.life.MapleLifeFactory; import server.life.MapleMonster; import server.life.MapleMonsterStats; import server.life.MobSkill; import server.life.MobSkillFactory; import server.maps.MapleMap; import server.maps.MapleNodes.MapleNodeInfo; import server.movement.LifeMovementFragment; import tools.FileoutputUtil; import tools.MaplePacketCreator; import tools.Pair; import tools.Triple; import tools.data.input.SeekableLittleEndianAccessor; import tools.packet.MobPacket; public final class MobHandler { public static void MoveMonster(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { if (chr == null || chr.getMap() == null) { return; } MapleMonster monster = chr.getMap().getMonsterByOid(slea.readInt()); if (monster == null) { return; } if (monster.getLinkCID() > 0) { return; } short moveid = slea.readShort(); boolean useSkill = (slea.readByte() & 0xFF) > 0; int skillId = slea.readByte(); int skillLevel = 0; int start_x = slea.readShort(); // hmm.. startpos? int start_y = slea.readShort(); // hmm... slea.readShort(); slea.readShort(); final List<LifeMovementFragment> res; try { res = MovementParse.parseMovement(slea, 2); } catch (ArrayIndexOutOfBoundsException e) { FileoutputUtil.outputFileError(FileoutputUtil.Movement_Mob, e); FileoutputUtil.log(FileoutputUtil.Movement_Mob, "怪物ID " + monster.getId() + ", AIOBE Type2:\r\n" + slea.toString(true)); return; } if ((res != null) && (res.size() > 0)) { MapleMap map = chr.getMap(); c.getSession().write(MobPacket.moveMonsterResponse(monster.getObjectId(), moveid, monster.getMp(), monster.isControllerHasAggro(), skillId, skillLevel)); if (slea.available() != 1) { FileoutputUtil.log("slea.available != 1 (怪物移动错误) 剩余封包长度: " + slea.available()); FileoutputUtil.log(FileoutputUtil.Movement_Mob, "slea.available != 36 (怪物移动错误)\r\n怪物ID: " + monster.getId() + "\r\n" + slea.toString(true)); return; } MovementParse.updatePosition(res, monster, -1); Point endPos = monster.getTruePosition(); map.moveMonster(monster, endPos); map.broadcastMessage(chr, MobPacket.moveMonster(useSkill, slea, skillId, skillLevel, monster.getObjectId()), endPos); } } public static void FriendlyDamage(SeekableLittleEndianAccessor slea, MapleCharacter chr) { MapleMap map = chr.getMap(); if (map == null) { return; } MapleMonster mobfrom = map.getMonsterByOid(slea.readInt()); slea.skip(4); MapleMonster mobto = map.getMonsterByOid(slea.readInt()); if ((mobfrom != null) && (mobto != null) && (mobto.getStats().isFriendly())) { int damage = mobto.getStats().getLevel() * Randomizer.nextInt(mobto.getStats().getLevel()) / 2; mobto.damage(chr, damage, true); checkShammos(chr, mobto, map); } } @SuppressWarnings("empty-statement") public static void MobBomb(SeekableLittleEndianAccessor slea, MapleCharacter chr) { MapleMap map = chr.getMap(); if (map == null) { return; } MapleMonster mobfrom = map.getMonsterByOid(slea.readInt()); slea.skip(4); slea.readInt(); } public static void checkShammos(MapleCharacter chr, MapleMonster mobto, MapleMap map) { MapleMap mapp; if ((!mobto.isAlive()) && (mobto.getStats().isEscort())) { for (MapleCharacter chrz : map.getCharactersThreadsafe()) { if ((chrz.getParty() != null) && (chrz.getParty().getLeader().getId() == chrz.getId())) { if (!chrz.haveItem(2022698)) { break; } MapleInventoryManipulator.removeById(chrz.getClient(), MapleInventoryType.USE, 2022698, 1, false, true); mobto.heal((int) mobto.getMobMaxHp(), mobto.getMobMaxMp(), true); return; } } map.broadcastMessage(MaplePacketCreator.serverMessageRedText("Your party has failed to protect the monster.")); mapp = chr.getMap().getForcedReturnMap(); for (MapleCharacter chrz : map.getCharactersThreadsafe()) { chrz.changeMap(mapp, mapp.getPortal(0)); } } else if ((mobto.getStats().isEscort()) && (mobto.getEventInstance() != null)) { mobto.getEventInstance().setProperty("HP", String.valueOf(mobto.getHp())); } } public static void MonsterBomb(int oid, MapleCharacter chr) { MapleMonster monster = chr.getMap().getMonsterByOid(oid); if ((monster == null) || (!chr.isAlive()) || (chr.isHidden()) || (monster.getLinkCID() > 0)) { return; } byte selfd = monster.getStats().getSelfD(); if (selfd != -1) { chr.getMap().killMonster(monster, chr, false, false, selfd); } } public static void AutoAggro(int monsteroid, MapleCharacter chr, SeekableLittleEndianAccessor slea) { if ((chr == null) || (chr.getMap() == null) || (chr.isHidden())) { return; } MapleMonster monster = chr.getMap().getMonsterByOid(monsteroid); if ((monster != null) && (chr.getTruePosition().distanceSq(monster.getTruePosition()) < 200000.0D) && (monster.getLinkCID() <= 0)) { if (monster.getController() != null) { if (chr.getMap().getCharacterById(monster.getController().getId()) == null) { monster.switchController(chr, true); } else { monster.switchController(monster.getController(), true); } } else { monster.switchController(chr, true); } } } public static void HypnotizeDmg(SeekableLittleEndianAccessor slea, MapleCharacter chr) { int oid = slea.readInt(); MapleMonster mob_from = chr.getMap().getMonsterByOid(oid); slea.skip(4); int to = slea.readInt(); slea.skip(1); slea.skip(1); int damage = slea.readInt(); MapleMonster mob_to = chr.getMap().getMonsterByOid(to); if ((mob_from != null) && (mob_to != null) && (mob_to.getStats().isFriendly())) { if (damage > 30000) { return; } mob_to.damage(chr, damage, true); checkShammos(chr, mob_to, chr.getMap()); } } public static void DisplayNode(SeekableLittleEndianAccessor slea, MapleCharacter chr) { MapleMonster mob_from = chr.getMap().getMonsterByOid(slea.readInt()); if (mob_from != null) { chr.getClient().getSession().write(MobPacket.getNodeProperties(mob_from, chr.getMap())); } } public static void MobNode(SeekableLittleEndianAccessor slea, MapleCharacter chr) { MapleMonster mob_from = chr.getMap().getMonsterByOid(slea.readInt()); int newNode = slea.readInt(); int nodeSize = chr.getMap().getNodes().size(); if ((mob_from != null) && (nodeSize > 0)) { MapleNodeInfo mni = chr.getMap().getNode(newNode); if (mni == null) { return; } mob_from.setLastNode(newNode); if (chr.getMap().isLastNode(newNode)) { switch (chr.getMapId() / 100) { case 9211200: case 9211201: case 9211202: case 9211203: case 9211204: case 9320001: case 9320002: case 9320003: chr.getMap().broadcastMessage(MaplePacketCreator.serverMessageRedText("进入下一个阶段。")); chr.getMap().removeMonster(mob_from); } } } } public static void RenameFamiliar(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { MonsterFamiliar mf = (MonsterFamiliar) c.getPlayer().getFamiliars().get(Integer.valueOf(slea.readInt())); String newName = slea.readMapleAsciiString(); if ((mf != null) && (mf.getName().equals(mf.getOriginalName())) && (MapleCharacterUtil.isEligibleCharName(newName, false))) { mf.setName(newName); } else { chr.dropMessage(1, "Name was not eligible."); } c.getSession().write(MaplePacketCreator.enableActions()); } public static void SpawnFamiliar(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { int mId = slea.readInt(); c.getSession().write(MaplePacketCreator.enableActions()); c.getPlayer().removeFamiliar(); if ((c.getPlayer().getFamiliars().containsKey(mId)) && (slea.readByte() > 0)) { MonsterFamiliar mf = (MonsterFamiliar) c.getPlayer().getFamiliars().get(Integer.valueOf(mId)); if (mf.getFatigue() > 0) { c.getPlayer().dropMessage(1, "Please wait " + mf.getFatigue() + " seconds to summon it."); } else { c.getPlayer().spawnFamiliar(mf); } } } public static void MoveFamiliar(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { slea.skip(13); List res = MovementParse.parseMovement(slea, 6); if ((chr != null) && (chr.getSummonedFamiliar() != null) && (res.size() > 0)) { Point pos = chr.getSummonedFamiliar().getPosition(); MovementParse.updatePosition(res, chr.getSummonedFamiliar(), 0); chr.getSummonedFamiliar().updatePosition(res); if (!chr.isHidden()) { chr.getMap().broadcastMessage(chr, MaplePacketCreator.moveFamiliar(chr.getId(), pos, res), chr.getTruePosition()); } } } public static void AttackFamiliar(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { if (chr.getSummonedFamiliar() == null) { return; } slea.skip(6); int skillid = slea.readInt(); SkillFactory.FamiliarEntry f = SkillFactory.getFamiliar(skillid); if (f == null) { return; } byte unk = slea.readByte(); byte size = slea.readByte(); List<Triple<Integer, Integer, List<Integer>>> attackPair = new ArrayList(size); for (int i = 0; i < size; i++) { int oid = slea.readInt(); int type = slea.readInt(); slea.skip(10); byte si = slea.readByte(); List attack = new ArrayList(si); for (int x = 0; x < si; x++) { attack.add(slea.readInt()); } attackPair.add(new Triple(oid, type, attack)); } MapleMonsterStats oStats = chr.getSummonedFamiliar().getOriginalStats(); chr.getMap().broadcastMessage(chr, MaplePacketCreator.familiarAttack(chr.getId(), unk, attackPair), chr.getTruePosition()); for (Triple attack : attackPair) { MapleMonster mons = chr.getMap().getMonsterByOid(((Integer) attack.left).intValue()); if ((mons == null) || (!mons.isAlive()) || (mons.getStats().isFriendly()) || (mons.getLinkCID() > 0) || (((List) attack.right).size() > f.attackCount)) { continue; } for (Iterator i$ = ((List) attack.right).iterator(); i$.hasNext();) { int damage = ((Integer) i$.next()); if (damage <= oStats.getPhysicalAttack() * 4) { mons.damage(chr, damage, true); } } if ((f.makeChanceResult()) && (mons.isAlive())) { for (MonsterStatus s : f.status) { mons.applyStatus(chr, new MonsterStatusEffect(s, (int) f.speed, MonsterStatus.genericSkill(s), null, false), false, f.time * 1000, false, null); } if (f.knockback) { mons.switchController(chr, true); } } } chr.getSummonedFamiliar().addFatigue(chr, attackPair.size()); } public static void TouchFamiliar(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { if (chr.getSummonedFamiliar() == null) { return; } slea.skip(6); byte unk = slea.readByte(); MapleMonster target = chr.getMap().getMonsterByOid(slea.readInt()); if (target == null) { return; } int type = slea.readInt(); slea.skip(4); int damage = slea.readInt(); int maxDamage = chr.getSummonedFamiliar().getOriginalStats().getPhysicalAttack() * 5; if (damage < maxDamage) { damage = maxDamage; } if ((!target.getStats().isFriendly()) ) { chr.getMap().broadcastMessage(chr, MaplePacketCreator.touchFamiliar(chr.getId(), unk, target.getObjectId(), type, 600, damage), chr.getTruePosition()); target.damage(chr, damage, true); chr.getSummonedFamiliar().addFatigue(chr); } } public static void UseFamiliar(SeekableLittleEndianAccessor slea, MapleClient c, MapleCharacter chr) { if ((chr == null) || (!chr.isAlive()) || (chr.getMap() == null) || (chr.hasBlockedInventory())) { c.getSession().write(MaplePacketCreator.enableActions()); return; } short slot = slea.readShort(); int itemId = slea.readInt(); Item toUse = chr.getInventory(MapleInventoryType.USE).getItem(slot); c.getSession().write(MaplePacketCreator.enableActions()); if ((toUse == null) || (toUse.getQuantity() < 1) || (toUse.getItemId() != itemId) || (itemId / 10000 != 287)) { return; } StructFamiliar f = MapleItemInformationProvider.getInstance().getFamiliarByItem(itemId); if (MapleLifeFactory.getMonsterStats(f.mob).getLevel() <= c.getPlayer().getLevel()) { MonsterFamiliar mf = (MonsterFamiliar) c.getPlayer().getFamiliars().get(Integer.valueOf(f.familiar)); if (mf != null) { if (mf.getVitality() >= 3) { mf.setExpiry(Math.min(System.currentTimeMillis() + 7776000000L, mf.getExpiry() + 2592000000L)); } else { mf.setVitality(mf.getVitality() + 1); mf.setExpiry(mf.getExpiry() + 2592000000L); } } else { mf = new MonsterFamiliar(c.getPlayer().getId(), f.familiar, System.currentTimeMillis() + 2592000000L); c.getPlayer().getFamiliars().put(f.familiar, mf); } MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, (short) 1, false, false); c.getSession().write(MaplePacketCreator.registerFamiliar(mf)); } } }