Search in sources :

Example 6 with MapleMonster

use of server.life.MapleMonster in project HeavenMS by ronancpl.

the class MoveLifeHandler method handlePacket.

@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
    int objectid = slea.readInt();
    short moveid = slea.readShort();
    MapleMapObject mmo = c.getPlayer().getMap().getMapObject(objectid);
    if (mmo == null || mmo.getType() != MapleMapObjectType.MONSTER) {
        return;
    }
    MapleMonster monster = (MapleMonster) mmo;
    List<LifeMovementFragment> res = null;
    List<MapleCharacter> banishPlayers = new ArrayList<>();
    byte pNibbles = slea.readByte();
    byte rawActivity = slea.readByte();
    byte useSkillId = slea.readByte();
    byte useSkillLevel = slea.readByte();
    short pOption = slea.readShort();
    slea.skip(8);
    if (rawActivity >= 0) {
        rawActivity = (byte) (rawActivity & 0xFF >> 1);
    }
    boolean isAttack = inRangeInclusive(rawActivity, 12, 20);
    boolean isSkill = inRangeInclusive(rawActivity, 21, 25);
    byte attackId = (byte) (isAttack ? rawActivity - 12 : -1);
    boolean nextMovementCouldBeSkill = (pNibbles & 0x0F) != 0;
    boolean pUnk = (pNibbles & 0xF0) != 0;
    int nextCastSkill = useSkillId;
    int nextCastSkillLevel = useSkillLevel;
    MobSkill toUse = null;
    int percHpLeft = (int) (((float) monster.getHp() / monster.getMaxHp()) * 100);
    if (nextMovementCouldBeSkill && monster.getNoSkills() > 0) {
        int Random = Randomizer.nextInt(monster.getNoSkills());
        Pair<Integer, Integer> skillToUse = monster.getSkills().get(Random);
        nextCastSkill = skillToUse.getLeft();
        nextCastSkillLevel = skillToUse.getRight();
        toUse = MobSkillFactory.getMobSkill(nextCastSkill, nextCastSkillLevel);
        if (isSkill || isAttack) {
            if (nextCastSkill != toUse.getSkillId() || nextCastSkillLevel != toUse.getSkillLevel()) {
                // toUse.resetAnticipatedSkill();
                return;
            } else if (toUse.getHP() < percHpLeft) {
                toUse = null;
            } else if (monster.canUseSkill(toUse)) {
                toUse.applyEffect(c.getPlayer(), monster, true, banishPlayers);
            // System.out.println("Applied: " + nextCastSkill + " Level: " + nextCastSkillLevel);
            }
        } else {
            MobAttackInfo mobAttack = MobAttackInfoFactory.getMobAttackInfo(monster, attackId);
        // System.out.println("Attacked");
        }
    }
    slea.readByte();
    // whatever
    slea.readInt();
    // hmm.. startpos?
    short start_x = slea.readShort();
    // hmm...
    short start_y = slea.readShort();
    Point startPos = new Point(start_x, start_y);
    res = parseMovement(slea);
    if (monster.getController() != c.getPlayer()) {
        if (monster.isAttackedBy(c.getPlayer())) {
            monster.switchController(c.getPlayer(), true);
        } else {
            return;
        }
    } else if (rawActivity == -1 && monster.isControllerKnowsAboutAggro() && !monster.isMobile() && !monster.isFirstAttack()) {
        monster.setControllerHasAggro(false);
        monster.setControllerKnowsAboutAggro(false);
    }
    boolean aggro = monster.isControllerHasAggro();
    if (toUse != null) {
        c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, monster.getMp(), aggro, toUse.getSkillId(), toUse.getSkillLevel()));
    } else {
        c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, monster.getMp(), aggro));
    }
    if (aggro) {
        monster.setControllerKnowsAboutAggro(true);
    }
    if (res != null) {
        c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, res), monster.getPosition());
        updatePosition(res, monster, -1);
        c.getPlayer().getMap().moveMonster(monster, monster.getPosition());
    }
    for (MapleCharacter chr : banishPlayers) {
        chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
    }
}
Also used : MapleCharacter(client.MapleCharacter) ArrayList(java.util.ArrayList) MapleMapObject(server.maps.MapleMapObject) MobAttackInfo(server.life.MobAttackInfo) Point(java.awt.Point) Point(java.awt.Point) LifeMovementFragment(server.movement.LifeMovementFragment) MobSkill(server.life.MobSkill) MapleMonster(server.life.MapleMonster)

Example 7 with MapleMonster

use of server.life.MapleMonster in project HeavenMS by ronancpl.

the class MapleMap method softKillAllMonsters.

public void softKillAllMonsters() {
    closeMapSpawnPoints();
    for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) {
        MapleMonster monster = (MapleMonster) monstermo;
        if (monster.getStats().isFriendly()) {
            continue;
        }
        spawnedMonstersOnMap.decrementAndGet();
        monster.setHpZero();
        removeMapObject(monster);
        monster.dispatchMonsterKilled(false);
    }
}
Also used : Point(java.awt.Point) SpawnPoint(server.life.SpawnPoint) MapleMonster(server.life.MapleMonster)

Example 8 with MapleMonster

use of server.life.MapleMonster in project HeavenMS by ronancpl.

the class MapleMap method killAllMonsters.

public void killAllMonsters() {
    closeMapSpawnPoints();
    for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) {
        MapleMonster monster = (MapleMonster) monstermo;
        killMonster(monster, null, false, 1);
    }
}
Also used : Point(java.awt.Point) SpawnPoint(server.life.SpawnPoint) MapleMonster(server.life.MapleMonster)

Example 9 with MapleMonster

use of server.life.MapleMonster in project HeavenMS by ronancpl.

the class MapleMapFactory method loadMapFromWz.

private synchronized MapleMap loadMapFromWz(int mapid, Integer omapid) {
    MapleMap map;
    mapsRLock.lock();
    try {
        map = maps.get(omapid);
    } finally {
        mapsRLock.unlock();
    }
    if (map != null) {
        return map;
    }
    String mapName = getMapName(mapid);
    MapleData mapData = source.getData(mapName);
    MapleData infoData = mapData.getChildByPath("info");
    String link = MapleDataTool.getString(infoData.getChildByPath("link"), "");
    if (!link.equals("")) {
        // nexon made hundreds of dojo maps so to reduce the size they added links.
        mapName = getMapName(Integer.parseInt(link));
        mapData = source.getData(mapName);
    }
    float monsterRate = 0;
    MapleData mobRate = infoData.getChildByPath("mobRate");
    if (mobRate != null) {
        monsterRate = ((Float) mobRate.getData()).floatValue();
    }
    map = new MapleMap(mapid, world, channel, MapleDataTool.getInt("returnMap", infoData), monsterRate);
    map.setEventInstance(event);
    String onFirstEnter = MapleDataTool.getString(infoData.getChildByPath("onFirstUserEnter"), String.valueOf(mapid));
    map.setOnFirstUserEnter(onFirstEnter.equals("") ? String.valueOf(mapid) : onFirstEnter);
    String onEnter = MapleDataTool.getString(infoData.getChildByPath("onUserEnter"), String.valueOf(mapid));
    map.setOnUserEnter(onEnter.equals("") ? String.valueOf(mapid) : onEnter);
    map.setFieldLimit(MapleDataTool.getInt(infoData.getChildByPath("fieldLimit"), 0));
    map.setMobInterval((short) MapleDataTool.getInt(infoData.getChildByPath("createMobInterval"), 5000));
    PortalFactory portalFactory = new PortalFactory();
    for (MapleData portal : mapData.getChildByPath("portal")) {
        map.addPortal(portalFactory.makePortal(MapleDataTool.getInt(portal.getChildByPath("pt")), portal));
    }
    MapleData timeMob = infoData.getChildByPath("timeMob");
    if (timeMob != null) {
        map.timeMob(MapleDataTool.getInt(timeMob.getChildByPath("id")), MapleDataTool.getString(timeMob.getChildByPath("message")));
    }
    int[] bounds = new int[4];
    bounds[0] = MapleDataTool.getInt(infoData.getChildByPath("VRTop"));
    bounds[1] = MapleDataTool.getInt(infoData.getChildByPath("VRBottom"));
    if (bounds[0] == bounds[1]) {
        // old-style baked map
        MapleData minimapData = mapData.getChildByPath("miniMap");
        if (minimapData != null) {
            bounds[0] = MapleDataTool.getInt(minimapData.getChildByPath("centerX")) * -1;
            bounds[1] = MapleDataTool.getInt(minimapData.getChildByPath("centerY")) * -1;
            bounds[2] = MapleDataTool.getInt(minimapData.getChildByPath("height"));
            bounds[3] = MapleDataTool.getInt(minimapData.getChildByPath("width"));
            map.setMapPointBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
        } else {
            int dist = (1 << 18);
            map.setMapPointBoundings(-dist / 2, -dist / 2, dist, dist);
        }
    } else {
        bounds[2] = MapleDataTool.getInt(infoData.getChildByPath("VRLeft"));
        bounds[3] = MapleDataTool.getInt(infoData.getChildByPath("VRRight"));
        map.setMapLineBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
    }
    List<MapleFoothold> allFootholds = new LinkedList<>();
    Point lBound = new Point();
    Point uBound = new Point();
    for (MapleData footRoot : mapData.getChildByPath("foothold")) {
        for (MapleData footCat : footRoot) {
            for (MapleData footHold : footCat) {
                int x1 = MapleDataTool.getInt(footHold.getChildByPath("x1"));
                int y1 = MapleDataTool.getInt(footHold.getChildByPath("y1"));
                int x2 = MapleDataTool.getInt(footHold.getChildByPath("x2"));
                int y2 = MapleDataTool.getInt(footHold.getChildByPath("y2"));
                MapleFoothold fh = new MapleFoothold(new Point(x1, y1), new Point(x2, y2), Integer.parseInt(footHold.getName()));
                fh.setPrev(MapleDataTool.getInt(footHold.getChildByPath("prev")));
                fh.setNext(MapleDataTool.getInt(footHold.getChildByPath("next")));
                if (fh.getX1() < lBound.x) {
                    lBound.x = fh.getX1();
                }
                if (fh.getX2() > uBound.x) {
                    uBound.x = fh.getX2();
                }
                if (fh.getY1() < lBound.y) {
                    lBound.y = fh.getY1();
                }
                if (fh.getY2() > uBound.y) {
                    uBound.y = fh.getY2();
                }
                allFootholds.add(fh);
            }
        }
    }
    MapleFootholdTree fTree = new MapleFootholdTree(lBound, uBound);
    for (MapleFoothold fh : allFootholds) {
        fTree.insert(fh);
    }
    map.setFootholds(fTree);
    if (mapData.getChildByPath("area") != null) {
        for (MapleData area : mapData.getChildByPath("area")) {
            int x1 = MapleDataTool.getInt(area.getChildByPath("x1"));
            int y1 = MapleDataTool.getInt(area.getChildByPath("y1"));
            int x2 = MapleDataTool.getInt(area.getChildByPath("x2"));
            int y2 = MapleDataTool.getInt(area.getChildByPath("y2"));
            map.addMapleArea(new Rectangle(x1, y1, (x2 - x1), (y2 - y1)));
        }
    }
    try {
        Connection con = DatabaseConnection.getConnection();
        try (PreparedStatement ps = con.prepareStatement("SELECT * FROM playernpcs WHERE map = ?")) {
            ps.setInt(1, omapid);
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    map.addMapObject(new PlayerNPCs(rs));
                }
            }
        }
        con.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    for (MapleData life : mapData.getChildByPath("life")) {
        String id = MapleDataTool.getString(life.getChildByPath("id"));
        String type = MapleDataTool.getString(life.getChildByPath("type"));
        AbstractLoadedMapleLife myLife = loadLife(life, id, type);
        if (myLife instanceof MapleMonster) {
            MapleMonster monster = (MapleMonster) myLife;
            int mobTime = MapleDataTool.getInt("mobTime", life, 0);
            int team = MapleDataTool.getInt("team", life, -1);
            if (mobTime == -1) {
                // does not respawn, force spawn once
                map.spawnMonster(monster);
            } else {
                map.addMonsterSpawn(monster, mobTime, team);
            }
            // should the map be reseted, use allMonsterSpawn list of monsters to spawn them again
            map.addAllMonsterSpawn(monster, mobTime, team);
        } else {
            map.addMapObject(myLife);
        }
    }
    if (mapData.getChildByPath("reactor") != null) {
        for (MapleData reactor : mapData.getChildByPath("reactor")) {
            String id = MapleDataTool.getString(reactor.getChildByPath("id"));
            if (id != null) {
                MapleReactor newReactor = loadReactor(reactor, id);
                map.spawnReactor(newReactor);
            }
        }
    }
    try {
        map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(omapid)), ""));
        map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(omapid)), ""));
    } catch (Exception e) {
        if (omapid / 1000 != 1020) {
            // explorer job introducion scenes
            e.printStackTrace();
            System.err.println("Not found mapid " + omapid);
        }
        map.setMapName("");
        map.setStreetName("");
    }
    map.setClock(mapData.getChildByPath("clock") != null);
    map.setEverlast(infoData.getChildByPath("everlast") != null);
    map.setTown(infoData.getChildByPath("town") != null);
    map.setHPDec(MapleDataTool.getIntConvert("decHP", infoData, 0));
    map.setHPDecProtect(MapleDataTool.getIntConvert("protectItem", infoData, 0));
    map.setForcedReturnMap(MapleDataTool.getInt(infoData.getChildByPath("forcedReturn"), 999999999));
    map.setBoat(mapData.getChildByPath("shipObj") != null);
    map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", infoData, -1));
    map.setFieldType(MapleDataTool.getIntConvert("fieldType", infoData, 0));
    // Is there a map that contains more than 500 mobs?
    map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", infoData, 500));
    HashMap<Integer, Integer> backTypes = new HashMap<>();
    try {
        for (MapleData layer : mapData.getChildByPath("back")) {
            // yolo
            int layerNum = Integer.parseInt(layer.getName());
            int btype = MapleDataTool.getInt(layer.getChildByPath("type"), 0);
            backTypes.put(layerNum, btype);
        }
    } catch (Exception e) {
        e.printStackTrace();
    // swallow cause I'm cool
    }
    map.setBackgroundTypes(backTypes);
    map.generateMapDropRangeCache();
    mapsWLock.lock();
    try {
        maps.put(omapid, map);
    } finally {
        mapsWLock.unlock();
    }
    return map;
}
Also used : SQLException(java.sql.SQLException) HashMap(java.util.HashMap) Rectangle(java.awt.Rectangle) ResultSet(java.sql.ResultSet) MapleData(provider.MapleData) DatabaseConnection(tools.DatabaseConnection) Connection(java.sql.Connection) PreparedStatement(java.sql.PreparedStatement) Point(java.awt.Point) AbstractLoadedMapleLife(server.life.AbstractLoadedMapleLife) Point(java.awt.Point) LinkedList(java.util.LinkedList) SQLException(java.sql.SQLException) PortalFactory(server.PortalFactory) MapleMonster(server.life.MapleMonster)

Example 10 with MapleMonster

use of server.life.MapleMonster in project HeavenMS by ronancpl.

the class AbstractDealDamageHandler method parseDamage.

protected AttackInfo parseDamage(LittleEndianAccessor lea, MapleCharacter chr, boolean ranged, boolean magic) {
    // 2C 00 00 01 91 A1 12 00 A5 57 62 FC E2 75 99 10 00 47 80 01 04 01 C6 CC 02 DD FF 5F 00
    AttackInfo ret = new AttackInfo();
    lea.readByte();
    ret.numAttackedAndDamage = lea.readByte();
    ret.numAttacked = (ret.numAttackedAndDamage >>> 4) & 0xF;
    ret.numDamage = ret.numAttackedAndDamage & 0xF;
    ret.allDamage = new HashMap<>();
    ret.skill = lea.readInt();
    ret.ranged = ranged;
    ret.magic = magic;
    if (ret.skill > 0) {
        ret.skilllevel = chr.getSkillLevel(ret.skill);
        if (ret.skilllevel == 0 && GameConstants.isPqSkillMap(chr.getMapId()) && GameConstants.isPqSkill(ret.skill))
            ret.skilllevel = 1;
    }
    if (ret.skill == Evan.ICE_BREATH || ret.skill == Evan.FIRE_BREATH || ret.skill == FPArchMage.BIG_BANG || ret.skill == ILArchMage.BIG_BANG || ret.skill == Bishop.BIG_BANG || ret.skill == Gunslinger.GRENADE || ret.skill == Brawler.CORKSCREW_BLOW || ret.skill == ThunderBreaker.CORKSCREW_BLOW || ret.skill == NightWalker.POISON_BOMB) {
        ret.charge = lea.readInt();
    } else {
        ret.charge = 0;
    }
    if (ret.skill == Paladin.HEAVENS_HAMMER) {
        ret.isHH = true;
    } else if (ret.skill == Aran.COMBO_TEMPEST) {
        ret.isTempest = true;
    }
    lea.skip(8);
    ret.display = lea.readByte();
    ret.direction = lea.readByte();
    ret.stance = lea.readByte();
    if (ret.skill == ChiefBandit.MESO_EXPLOSION) {
        if (ret.numAttackedAndDamage == 0) {
            lea.skip(10);
            int bullets = lea.readByte();
            for (int j = 0; j < bullets; j++) {
                int mesoid = lea.readInt();
                lea.skip(1);
                ret.allDamage.put(Integer.valueOf(mesoid), null);
            }
            return ret;
        } else {
            lea.skip(6);
        }
        for (int i = 0; i < ret.numAttacked + 1; i++) {
            int oid = lea.readInt();
            if (i < ret.numAttacked) {
                lea.skip(12);
                int bullets = lea.readByte();
                List<Integer> allDamageNumbers = new ArrayList<>();
                for (int j = 0; j < bullets; j++) {
                    int damage = lea.readInt();
                    allDamageNumbers.add(Integer.valueOf(damage));
                }
                ret.allDamage.put(Integer.valueOf(oid), allDamageNumbers);
                lea.skip(4);
            } else {
                int bullets = lea.readByte();
                for (int j = 0; j < bullets; j++) {
                    int mesoid = lea.readInt();
                    lea.skip(1);
                    ret.allDamage.put(Integer.valueOf(mesoid), null);
                }
            }
        }
        return ret;
    }
    if (ranged) {
        lea.readByte();
        ret.speed = lea.readByte();
        lea.readByte();
        ret.rangedirection = lea.readByte();
        lea.skip(7);
        if (ret.skill == Bowmaster.HURRICANE || ret.skill == Marksman.PIERCING_ARROW || ret.skill == Corsair.RAPID_FIRE || ret.skill == WindArcher.HURRICANE) {
            lea.skip(4);
        }
    } else {
        lea.readByte();
        ret.speed = lea.readByte();
        lea.skip(4);
    }
    // Find the base damage to base futher calculations on.
    // Several skills have their own formula in this section.
    int calcDmgMax = 0;
    if (magic && ret.skill != 0) {
        calcDmgMax = (chr.getTotalMagic() * chr.getTotalMagic() / 1000 + chr.getTotalMagic()) / 30 + chr.getTotalInt() / 200;
    } else if (ret.skill == 4001344 || ret.skill == NightWalker.LUCKY_SEVEN || ret.skill == NightLord.TRIPLE_THROW) {
        calcDmgMax = (chr.getTotalLuk() * 5) * chr.getTotalWatk() / 100;
    } else if (ret.skill == DragonKnight.DRAGON_ROAR) {
        calcDmgMax = (chr.getTotalStr() * 4 + chr.getTotalDex()) * chr.getTotalWatk() / 100;
    } else if (ret.skill == NightLord.VENOMOUS_STAR || ret.skill == Shadower.VENOMOUS_STAB) {
        calcDmgMax = (int) (18.5 * (chr.getTotalStr() + chr.getTotalLuk()) + chr.getTotalDex() * 2) / 100 * chr.calculateMaxBaseDamage(chr.getTotalWatk());
    } else {
        calcDmgMax = chr.calculateMaxBaseDamage(chr.getTotalWatk());
    }
    if (ret.skill != 0) {
        Skill skill = SkillFactory.getSkill(ret.skill);
        MapleStatEffect effect = skill.getEffect(ret.skilllevel);
        if (magic) {
            // Since the skill is magic based, use the magic formula
            if (chr.getJob() == MapleJob.IL_ARCHMAGE || chr.getJob() == MapleJob.IL_MAGE) {
                int skillLvl = chr.getSkillLevel(ILMage.ELEMENT_AMPLIFICATION);
                if (skillLvl > 0)
                    calcDmgMax = calcDmgMax * SkillFactory.getSkill(ILMage.ELEMENT_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
            } else if (chr.getJob() == MapleJob.FP_ARCHMAGE || chr.getJob() == MapleJob.FP_MAGE) {
                int skillLvl = chr.getSkillLevel(FPMage.ELEMENT_AMPLIFICATION);
                if (skillLvl > 0)
                    calcDmgMax = calcDmgMax * SkillFactory.getSkill(FPMage.ELEMENT_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
            } else if (chr.getJob() == MapleJob.BLAZEWIZARD3 || chr.getJob() == MapleJob.BLAZEWIZARD4) {
                int skillLvl = chr.getSkillLevel(BlazeWizard.ELEMENT_AMPLIFICATION);
                if (skillLvl > 0)
                    calcDmgMax = calcDmgMax * SkillFactory.getSkill(BlazeWizard.ELEMENT_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
            } else if (chr.getJob() == MapleJob.EVAN7 || chr.getJob() == MapleJob.EVAN8 || chr.getJob() == MapleJob.EVAN9 || chr.getJob() == MapleJob.EVAN10) {
                int skillLvl = chr.getSkillLevel(Evan.MAGIC_AMPLIFICATION);
                if (skillLvl > 0)
                    calcDmgMax = calcDmgMax * SkillFactory.getSkill(Evan.MAGIC_AMPLIFICATION).getEffect(skillLvl).getY() / 100;
            }
            calcDmgMax *= effect.getMatk();
            if (ret.skill == Cleric.HEAL) {
                // This formula is still a bit wonky, but it is fairly accurate.
                calcDmgMax = (int) Math.round((chr.getTotalInt() * 4.8 + chr.getTotalLuk() * 4) * chr.getTotalMagic() / 1000);
                calcDmgMax = calcDmgMax * effect.getHp() / 100;
            }
        } else if (ret.skill == Hermit.SHADOW_MESO) {
            // Shadow Meso also has its own formula
            calcDmgMax = effect.getMoneyCon() * 10;
            calcDmgMax = (int) Math.floor(calcDmgMax * 1.5);
        } else {
            // Normal damage formula for skills
            calcDmgMax = calcDmgMax * effect.getDamage() / 100;
        }
    }
    Integer comboBuff = chr.getBuffedValue(MapleBuffStat.COMBO);
    if (comboBuff != null && comboBuff > 0) {
        int oid = chr.isCygnus() ? DawnWarrior.COMBO : Crusader.COMBO;
        int advcomboid = chr.isCygnus() ? DawnWarrior.ADVANCED_COMBO : Hero.ADVANCED_COMBO;
        if (comboBuff > 6) {
            // Advanced Combo
            MapleStatEffect ceffect = SkillFactory.getSkill(advcomboid).getEffect(chr.getSkillLevel(advcomboid));
            calcDmgMax = (int) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + 0.20 + (comboBuff - 5) * 0.04);
        } else {
            // Normal Combo
            int skillLv = chr.getSkillLevel(oid);
            if (skillLv <= 0 || chr.isGM())
                skillLv = SkillFactory.getSkill(oid).getMaxLevel();
            if (skillLv > 0) {
                MapleStatEffect ceffect = SkillFactory.getSkill(oid).getEffect(skillLv);
                calcDmgMax = (int) Math.floor(calcDmgMax * (ceffect.getDamage() + 50) / 100 + Math.floor((comboBuff - 1) * (skillLv / 6)) / 100);
            }
        }
        if (GameConstants.isFinisherSkill(ret.skill)) {
            // Finisher skills do more damage based on how many orbs the player has.
            int orbs = comboBuff - 1;
            if (orbs == 2)
                calcDmgMax *= 1.2;
            else if (orbs == 3)
                calcDmgMax *= 1.54;
            else if (orbs == 4)
                calcDmgMax *= 2;
            else if (orbs >= 5)
                calcDmgMax *= 2.5;
        }
    }
    if (chr.getEnergyBar() == 15000) {
        int energycharge = chr.isCygnus() ? ThunderBreaker.ENERGY_CHARGE : Marauder.ENERGY_CHARGE;
        MapleStatEffect ceffect = SkillFactory.getSkill(energycharge).getEffect(chr.getSkillLevel(energycharge));
        calcDmgMax *= ceffect.getDamage() / 100;
    }
    if (chr.getMapId() >= 914000000 && chr.getMapId() <= 914000500) {
        // Aran Tutorial.
        calcDmgMax += 80000;
    }
    boolean canCrit = false;
    if (chr.getJob().isA((MapleJob.BOWMAN)) || chr.getJob().isA(MapleJob.THIEF) || chr.getJob().isA(MapleJob.NIGHTWALKER1) || chr.getJob().isA(MapleJob.WINDARCHER1) || chr.getJob() == MapleJob.ARAN3 || chr.getJob() == MapleJob.ARAN4 || chr.getJob() == MapleJob.MARAUDER || chr.getJob() == MapleJob.BUCCANEER) {
        canCrit = true;
    }
    if (chr.getBuffEffect(MapleBuffStat.SHARP_EYES) != null) {
        // Any class that has sharp eyes can crit. Also, since it stacks with normal crit go ahead
        // and calc it in.
        canCrit = true;
        calcDmgMax *= 1.4;
    }
    boolean shadowPartner = false;
    if (chr.getBuffEffect(MapleBuffStat.SHADOWPARTNER) != null) {
        shadowPartner = true;
    }
    if (ret.skill != 0) {
        int fixed = ret.getAttackEffect(chr, SkillFactory.getSkill(ret.skill)).getFixDamage();
        if (fixed > 0)
            calcDmgMax = fixed;
    }
    for (int i = 0; i < ret.numAttacked; i++) {
        int oid = lea.readInt();
        lea.skip(14);
        List<Integer> allDamageNumbers = new ArrayList<>();
        MapleMonster monster = chr.getMap().getMonsterByOid(oid);
        if (chr.getBuffEffect(MapleBuffStat.WK_CHARGE) != null) {
            // Charge, so now we need to check elemental effectiveness
            int sourceID = chr.getBuffSource(MapleBuffStat.WK_CHARGE);
            int level = chr.getBuffedValue(MapleBuffStat.WK_CHARGE);
            if (monster != null) {
                if (sourceID == WhiteKnight.BW_FIRE_CHARGE || sourceID == WhiteKnight.SWORD_FIRE_CHARGE) {
                    if (monster.getStats().getEffectiveness(Element.FIRE) == ElementalEffectiveness.WEAK) {
                        calcDmgMax *= 1.05 + level * 0.015;
                    }
                } else if (sourceID == WhiteKnight.BW_ICE_CHARGE || sourceID == WhiteKnight.SWORD_ICE_CHARGE) {
                    if (monster.getStats().getEffectiveness(Element.ICE) == ElementalEffectiveness.WEAK) {
                        calcDmgMax *= 1.05 + level * 0.015;
                    }
                } else if (sourceID == WhiteKnight.BW_LIT_CHARGE || sourceID == WhiteKnight.SWORD_LIT_CHARGE) {
                    if (monster.getStats().getEffectiveness(Element.LIGHTING) == ElementalEffectiveness.WEAK) {
                        calcDmgMax *= 1.05 + level * 0.015;
                    }
                } else if (sourceID == Paladin.BW_HOLY_CHARGE || sourceID == Paladin.SWORD_HOLY_CHARGE) {
                    if (monster.getStats().getEffectiveness(Element.HOLY) == ElementalEffectiveness.WEAK) {
                        calcDmgMax *= 1.2 + level * 0.015;
                    }
                }
            } else {
                // Since we already know the skill has an elemental attribute, but we dont know if the monster is weak or not, lets
                // take the safe approach and just assume they are weak.
                calcDmgMax *= 1.5;
            }
        }
        if (ret.skill != 0) {
            Skill skill = SkillFactory.getSkill(ret.skill);
            if (skill.getElement() != Element.NEUTRAL && chr.getBuffedValue(MapleBuffStat.ELEMENTAL_RESET) == null) {
                // The skill has an element effect, so we need to factor that in.
                if (monster != null) {
                    ElementalEffectiveness eff = monster.getElementalEffectiveness(skill.getElement());
                    if (eff == ElementalEffectiveness.WEAK) {
                        calcDmgMax *= 1.5;
                    } else if (eff == ElementalEffectiveness.STRONG) {
                    // calcDmgMax *= 0.5;
                    }
                } else {
                    // Since we already know the skill has an elemental attribute, but we dont know if the monster is weak or not, lets
                    // take the safe approach and just assume they are weak.
                    calcDmgMax *= 1.5;
                }
            }
            if (ret.skill == FPWizard.POISON_BREATH || ret.skill == FPMage.POISON_MIST || ret.skill == FPArchMage.FIRE_DEMON || ret.skill == ILArchMage.ICE_DEMON) {
                if (monster != null) {
                // Turns out poison is completely server side, so I don't know why I added this. >.<
                // calcDmgMax = monster.getHp() / (70 - chr.getSkillLevel(skill));
                }
            } else if (ret.skill == Hermit.SHADOW_WEB) {
                if (monster != null) {
                    calcDmgMax = monster.getHp() / (50 - chr.getSkillLevel(skill));
                }
            }
        }
        for (int j = 0; j < ret.numDamage; j++) {
            int damage = lea.readInt();
            int hitDmgMax = calcDmgMax;
            if (ret.skill == Buccaneer.BARRAGE) {
                if (j > 3)
                    hitDmgMax *= Math.pow(2, (j - 3));
            }
            if (shadowPartner) {
                // in for the crit effects.
                if (j >= ret.numDamage / 2) {
                    hitDmgMax *= 0.5;
                }
            }
            if (ret.skill == Marksman.SNIPE) {
                damage = 195000 + Randomizer.nextInt(5000);
                hitDmgMax = 200000;
            }
            int maxWithCrit = hitDmgMax;
            if (// They can crit, so up the max.
            canCrit)
                maxWithCrit *= 2;
            // Warn if the damage is over 1.5x what we calculated above.
            if (damage > maxWithCrit * 1.5) {
                AutobanFactory.DAMAGE_HACK.alert(chr, "DMG: " + damage + " MaxDMG: " + maxWithCrit + " SID: " + ret.skill + " MobID: " + (monster != null ? monster.getId() : "null") + " Map: " + chr.getMap().getMapName() + " (" + chr.getMapId() + ")");
            }
            // Add a ab point if its over 5x what we calculated.
            if (damage > maxWithCrit * 5) {
                AutobanFactory.DAMAGE_HACK.addPoint(chr.getAutobanManager(), "DMG: " + damage + " MaxDMG: " + maxWithCrit + " SID: " + ret.skill + " MobID: " + (monster != null ? monster.getId() : "null") + " Map: " + chr.getMap().getMapName() + " (" + chr.getMapId() + ")");
            }
            if (ret.skill == Marksman.SNIPE || (canCrit && damage > hitDmgMax)) {
                // If the skill is a crit, inverse the damage to make it show up on clients.
                damage = -Integer.MAX_VALUE + damage - 1;
            }
            allDamageNumbers.add(damage);
        }
        if (ret.skill != Corsair.RAPID_FIRE || ret.skill != Aran.HIDDEN_FULL_DOUBLE || ret.skill != Aran.HIDDEN_FULL_TRIPLE || ret.skill != Aran.HIDDEN_OVER_DOUBLE || ret.skill != Aran.HIDDEN_OVER_TRIPLE) {
            lea.skip(4);
        }
        ret.allDamage.put(Integer.valueOf(oid), allDamageNumbers);
    }
    if (ret.skill == NightWalker.POISON_BOMB) {
        // Poison Bomb
        lea.skip(4);
        ret.position.setLocation(lea.readShort(), lea.readShort());
    }
    return ret;
}
Also used : Skill(client.Skill) MobSkill(server.life.MobSkill) MapleStatEffect(server.MapleStatEffect) ArrayList(java.util.ArrayList) ElementalEffectiveness(server.life.ElementalEffectiveness) Point(java.awt.Point) MapleMonster(server.life.MapleMonster)

Aggregations

MapleMonster (server.life.MapleMonster)37 Point (java.awt.Point)20 MapleCharacter (client.MapleCharacter)15 SpawnPoint (server.life.SpawnPoint)13 ArrayList (java.util.ArrayList)9 MapleMapObject (server.maps.MapleMapObject)9 MapleMap (server.maps.MapleMap)7 Skill (client.Skill)6 MapleStatEffect (server.MapleStatEffect)6 MonsterStatusEffect (client.status.MonsterStatusEffect)5 Item (client.inventory.Item)4 SQLException (java.sql.SQLException)4 Rectangle (java.awt.Rectangle)3 IOException (java.io.IOException)3 UnknownHostException (java.net.UnknownHostException)3 Connection (java.sql.Connection)3 PreparedStatement (java.sql.PreparedStatement)3 MapleItemInformationProvider (server.MapleItemInformationProvider)3 MobSkill (server.life.MobSkill)3 MapleMapItem (server.maps.MapleMapItem)3