package handling.channel.handler; import java.util.*; import java.sql.ResultSet; import java.sql.PreparedStatement; import java.sql.Connection; import com.alibaba.fastjson.JSONObject; import database.DBConPool; import tools.packet.MobPacket; import server.SkillType; import server.MapleItemInformationProvider; import client.inventory.Equip; import tools.data.LittleEndianAccessor; import client.MapleJob; import java.awt.Point; import server.life.Element; import client.anticheat.CheatTracker; import client.inventory.IItem; import server.life.MapleMonsterStats; import server.life.MapleMonster; import client.PlayerStats; import server.maps.MapleMap; import java.util.Map.Entry; import client.inventory.MapleInventoryType; import client.status.MonsterStatusEffect; import server.Randomizer; import constants.tzjc; import client.SkillFactory; import java.awt.geom.Point2D; import constants.ServerConfig; import tools.Pair; import client.status.MonsterStatus; import server.maps.MapleMapObject; import server.maps.MapleMapItem; import server.maps.MapleMapObjectType; import tools.AttackPair; import gui.Start; import tools.FileoutputUtil; import handling.world.World.Broadcast; import client.MapleBuffStat; import constants.GameConstants; import tools.MaplePacketCreator; import client.anticheat.CheatingOffense; import server.MapleStatEffect; import client.MapleCharacter; import client.ISkill; import server.maps.MaplePvp; public class DamageParse { public static final Map MobRedDam = new HashMap(); public static void applyAttack(final AttackInfo attack, final ISkill theSkill, final MapleCharacter player, int attackCount, final double maxDamagePerMonster, final MapleStatEffect effect, final AttackType attack_type) { if (!player.isAlive()) { player.getCheatTracker().registerOffense(CheatingOffense.ATTACKING_WHILE_DEAD); return; } if (attack.real) { player.getCheatTracker().checkAttack(attack.skill, attack.lastAttackTickCount); } if (attack.skill != 0) { if (effect == null) { player.getClient().sendPacket(MaplePacketCreator.enableActions()); return; } if (GameConstants.isMulungSkill(attack.skill)) { if (player.getmulungEnergy() < 10000) { return; } if (player.getMapId() / 10000 != 92502) { return; } player.mulungEnergyModify(false); } if (GameConstants.isPyramidSkill(attack.skill) && (player.getMapId() / 1000000 != 926 || player.getPyramidSubway() == null || !player.getPyramidSubway().onSkillUse(player))) { return; } if (GameConstants.isAran((int) player.getJob())) { final int reduce = player.Aran_ReduceCombo(attack.skill); if (reduce > 0) { player.setCombo(player.getCombo() - reduce); } } int last = attackCount; boolean mirror_fix = false; if (player.getJob() >= 411 && player.getJob() <= 412) { mirror_fix = true; } if (player.getJob() >= 1400 && player.getJob() <= 1412) { mirror_fix = true; } if (attack.skill == 11101004) { last = 2; } if (attack.skill == 15111007) { last = 3; } last = 技能段数(attack.skill); if (mirror_fix || player.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) { last *= 2; } if (attack.hits > last) { if (player.hasGmLevel(1)) { player.dropMessage("攻击次数异常攻击次数 " + (int) attack.hits + " 服务端判断正常攻击次数 " + last + " 技能ID " + attack.skill); } else { Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 攻击次数异常已自动封锁。 玩家攻击次数 " + (int) attack.hits + " 服务端判断正常攻击次数 " + last + " 技能ID " + attack.skill)); FileoutputUtil.logToFile("logs/Hack/Ban/技能攻击次数.txt", "\r\n" + FileoutputUtil.NowTime() + "玩家: " + player.getName() + "(" + (int) player.getLevel() + ") 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 技能等级: " + player.getSkillLevel(attack.skill) + " 攻击次数 : " + (int) attack.hits + " 正常攻击次数 :" + last); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "技能攻击次数异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } final String reason = "使用违法程式练功"; if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为" + reason + "而被管理员永久停权。")); } } } int CheckCount = effect.getMobCount(); CheckCount = 技能个数(attack.skill); if (attack.targets > CheckCount) { if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/打怪数量异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家: " + player.getName() + "(" + (int) player.getLevel() + ") 地图: " + player.getMapId() + "技能代码: " + attack.skill + " 技能等级: " + player.getSkillLevel(effect.getSourceId()) + " 封包怪物量 : " + (int) attack.targets + " 服务端怪物量 :" + CheckCount); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 攻击怪物数量异常。 封包怪物量 " + (int) attack.targets + " 服务端怪物量 " + CheckCount + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "打怪数量异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } final String reason2 = "使用违法程式练功"; if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为" + reason2 + "而被管理员永久停权。")); } return; } player.dropMessage("打怪数量异常,技能代码: " + attack.skill + " 封包怪物量 : " + (int) attack.targets + " 服务端怪物量 :" + CheckCount); } } if (attack.hits > 0 && attack.targets > 0 && !player.getStat().checkEquipDurabilitys(player, -1)) { player.dropMessage(5, "耐久度已经归零"); return; } int totDamage = 0; final MapleMap map = player.getMap(); if (map.getId() == 990010000) { MaplePvp.doPvP(player, map, attack); } if (attack.skill == 4211006) { for (final AttackPair oned : attack.allDamage) { if (oned.attack != null) { continue; } final MapleMapObject mapobject = map.getMapObject(oned.objectid, MapleMapObjectType.ITEM); if (mapobject == null) { player.getCheatTracker().registerOffense(CheatingOffense.EXPLODING_NONEXISTANT); return; } final MapleMapItem mapitem = (MapleMapItem) mapobject; mapitem.getLock().lock(); try { if (mapitem.getMeso() <= 0) { player.getCheatTracker().registerOffense(CheatingOffense.ETC_EXPLOSION); return; } if (mapitem.isPickedUp()) { return; } map.removeMapObject((MapleMapObject) mapitem); map.broadcastMessage(MaplePacketCreator.explodeDrop(mapitem.getObjectId())); mapitem.setPickedUp(true); } finally { mapitem.getLock().unlock(); } } } int totDamageToOneMonster = 0; long newtotDamageToOneMonster = 0L; long hpMob = 0L; final PlayerStats stats = player.getStat(); final int CriticalDamage = stats.passive_sharpeye_percent(); byte ShdowPartnerAttackPercentage = 0; if (attack_type == AttackType.RANGED_WITH_SHADOWPARTNER || attack_type == AttackType.NON_RANGED_WITH_MIRROR) { MapleStatEffect shadowPartnerEffect; if (attack_type == AttackType.NON_RANGED_WITH_MIRROR) { shadowPartnerEffect = player.getStatForBuff(MapleBuffStat.MIRROR_IMAGE); } else { shadowPartnerEffect = player.getStatForBuff(MapleBuffStat.SHADOWPARTNER); } if (shadowPartnerEffect != null) { if (attack.skill != 0 && attack_type != AttackType.NON_RANGED_WITH_MIRROR) { ShdowPartnerAttackPercentage = (byte) shadowPartnerEffect.getY(); } else { ShdowPartnerAttackPercentage = (byte) shadowPartnerEffect.getX(); } } attackCount /= 2; } double maxDamagePerHit = 0.0; for (final AttackPair oned2 : attack.allDamage) { final MapleMonster monster = map.getMonsterByOid(oned2.objectid); if (monster != null) { totDamageToOneMonster = 0; newtotDamageToOneMonster = 0L; hpMob = monster.getHp(); final MapleMonsterStats monsterstats = monster.getStats(); final int fixeddmg = monsterstats.getFixedDamage(); final boolean Tempest = monster.getStatusSourceID(MonsterStatus.FREEZE) == 21120006; maxDamagePerHit = calculateMaxWeaponDamagePerHit(player, monster, attack, theSkill, effect, maxDamagePerMonster, Integer.valueOf(CriticalDamage)); byte overallAttackCount = 0; for (final Pair eachde : oned2.attack) { Integer eachd = (Integer) eachde.left; ++overallAttackCount; if (!GameConstants.isElseSkill(attack.skill)) { if (GameConstants.Novice_Skill(attack.skill) && eachd.intValue() > 40) { boolean apple = false; if (player.getBuffSource(MapleBuffStat.WATK) == 2022179 || player.getBuffSource(MapleBuffStat.MATK) == 2022179 || player.getBuffSource(MapleBuffStat.WDEF) == 2022179) { apple = true; } if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 最高伤害: 40 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss() + " 紫色蘋果: " + apple); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 40 本次伤害 " + eachd + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "伤害异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); } return; } player.dropMessage("[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 40 本次伤害 " + eachd + " 技能ID " + attack.skill); } boolean ban = false; int atk = 2140000001; if (eachd.intValue() < 0) { if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 伤害过低导致越界 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss()); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 伤害过低导致越界本次伤害 " + eachd + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "伤害异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); } return; } player.dropMessage("[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 伤害过低导致越界本次伤害 " + eachd + " 技能ID " + attack.skill); } if (!GameConstants.isAran((int) player.getJob())) { if (((Integer) Start.ConfigValuesMap.get("伤害检测")).intValue() > 0) { atk = ((Integer) Start.ConfigValuesMap.get("伤害上限")).intValue(); } if (eachd.intValue() >= atk && (double) eachd.intValue() > Math.ceil(maxDamagePerHit * 1.2)) { ban = true; } if ((long) eachd.intValue() == monster.getMobMaxHp()) { ban = false; } if (ban) { boolean apple2 = false; if (player.getBuffSource(MapleBuffStat.WATK) == 2022179 || player.getBuffSource(MapleBuffStat.MATK) == 2022179 || player.getBuffSource(MapleBuffStat.WDEF) == 2022179) { apple2 = true; } if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 最高伤害: " + atk + " 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss() + " 紫色蘋果: " + apple2); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 " + atk + " 本次伤害 " + eachd + " 技能ID " + attack.skill + "预计伤害: " + (int) maxDamagePerHit)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "伤害异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); } return; } player.dropMessage("[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 " + atk + " 本次伤害 " + eachd + " 技能ID " + attack.skill + "预计伤害: " + (int) maxDamagePerHit); } } atk = GameConstants.getMaxDamage((int) player.getLevel(), (int) player.getJob(), attack.skill); if (GameConstants.isAran((int) player.getJob())) { if (player.getLevel() > 10 && eachd.intValue() > atk && (double) eachd.intValue() > maxDamagePerHit * 2.0) { FileoutputUtil.logToFile("logs/Hack/伤害异常_狂狼.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 技能代码: " + attack.skill + " 怪物: " + monster.getId() + " 最高伤害: " + atk + " 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss()); } if (player.getLevel() <= 20) { atk = 1000; if (eachd.intValue() >= atk && (double) eachd.intValue() > maxDamagePerHit) { boolean apple2 = false; if (player.getBuffSource(MapleBuffStat.WATK) == 2022179 || player.getBuffSource(MapleBuffStat.MATK) == 2022179 || player.getBuffSource(MapleBuffStat.WDEF) == 2022179) { apple2 = true; } ban = true; FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 最高伤害: " + atk + " 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss() + " 紫色蘋果: " + apple2); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 " + atk + " 本次伤害 " + eachd + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); player.ban(player.getName() + "伤害异常", true, true, false); player.getClient().getSession().close(); return; } } } } else if (eachd.intValue() > atk && (double) eachd.intValue() > maxDamagePerHit * 2.0) { FileoutputUtil.logToFile("logs/Hack/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 技能代码: " + attack.skill + " 怪物: " + monster.getId() + " 最高伤害: " + atk + " 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss()); } } if (overallAttackCount - 1 == attackCount) { double min = maxDamagePerHit; final double shadow = ((double) ShdowPartnerAttackPercentage == 0.0) ? 1.0 : ((double) ShdowPartnerAttackPercentage); if (ShdowPartnerAttackPercentage != 0) { min = maxDamagePerHit / 100.0; } final double dam = monsterstats.isBoss() ? stats.bossdam_r : stats.dam_r; final double last2 = maxDamagePerHit = min * (shadow * dam / 100.0); } if (fixeddmg != -1) { if (monsterstats.getOnlyNoramlAttack()) { eachd = Integer.valueOf((attack.skill != 0) ? 0 : fixeddmg); } else { eachd = Integer.valueOf(fixeddmg); } } else if (monsterstats.getOnlyNoramlAttack()) { eachd = Integer.valueOf((attack.skill != 0) ? 0 : Math.min(eachd.intValue(), (int) maxDamagePerHit)); } else if (!player.isGM() && ((Integer) Start.ConfigValuesMap.get("伤害修正")).intValue() > 0) { if (!Tempest) { if (!monster.isBuffed(MonsterStatus.DAMAGE_IMMUNITY) && !monster.isBuffed(MonsterStatus.WEAPON_IMMUNITY) && !monster.isBuffed(MonsterStatus.WEAPON_DAMAGE_REFLECT)) { if ((double) eachd.intValue() > maxDamagePerHit) { player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE, "[伤害: " + eachd + ", 预期: " + maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 使用的技能: " + attack.skill + "]"); if ((double) eachd.intValue() > maxDamagePerHit * 2.0) { if ((double) eachd.intValue() > maxDamagePerHit * 2.0 && maxDamagePerHit != 1.0) { if (ServerConfig.LOG_DAMAGE) { FileoutputUtil.logToFile("Logs/hack/伤害计算/伤害计算修正_" + monster.getId() + "_" + attack.skill + ".txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家: " + player.getName() + "(" + (int) player.getLevel() + ") 职业: " + (int) player.getJob() + " 怪物:" + monster.getId() + " 封包伤害 :" + eachd + " 预计伤害 :" + (int) maxDamagePerHit + " 是否为BOSS: " + monster.getStats().isBoss(), false, false); } player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_2, "[伤害: " + eachd + ", 预计伤害: " + (int) maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 技能: " + attack.skill + "]"); } eachd = Integer.valueOf((int) (maxDamagePerHit * 2.0)); player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_2, "[伤害: " + eachd + ", 预期: " + maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 使用的技能: " + attack.skill + "]"); if (eachd.intValue() >= 10000) { player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_2, "[伤害: " + eachd + ", 预期: " + maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 使用的技能: " + attack.skill + "]"); } } } } else if ((double) eachd.intValue() > maxDamagePerHit) { eachd = Integer.valueOf((int) maxDamagePerHit); if ((double) eachd.intValue() > maxDamagePerHit * 2.0 && maxDamagePerHit != 1.0) { if (ServerConfig.LOG_DAMAGE) { FileoutputUtil.logToFile("Logs/hack/伤害计算/伤害计算修正_" + monster.getId() + "_" + attack.skill + ".txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家: " + player.getName() + "(" + (int) player.getLevel() + ") 职业: " + (int) player.getJob() + " 怪物:" + monster.getId() + " 封包伤害 :" + eachd + " 预计伤害 :" + (int) maxDamagePerHit + " 是否为BOSS: " + monster.getStats().isBoss()); } player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_2, "[伤害: " + eachd + ", 预计伤害: " + (int) maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 技能: " + attack.skill + "]"); } } } } totDamageToOneMonster += eachd.intValue(); newtotDamageToOneMonster += (long) eachd.intValue(); if (monster.getId() == 9300021 && player.getPyramidSubway() != null) { player.getPyramidSubway().onMiss(player); } } totDamage += totDamageToOneMonster; player.checkMonsterAggro(monster); final double range = player.getPosition().distanceSq((Point2D) monster.getPosition()); double SkillRange = GameConstants.getAttackRange(player, effect, attack); if (((Integer) Start.ConfigValuesMap.get("重置技能范围开关")).intValue() > 0) { SkillRange = (double) ((Integer) Start.ConfigValuesMap.get("重置技能总范围")).intValue(); } if (player.getDebugMessage() && range > SkillRange) { player.dropMessage("技能[" + attack.skill + "] 预计范围: " + (int) SkillRange + " 实際范围: " + (int) range + ""); } if (range > SkillRange && !player.inBossMap() && attack.skill != 5221004 && attack.skill != 21120006) { player.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER, "攻击范围异常,技能:" + attack.skill + "(" + SkillFactory.getName(attack.skill) + ")\u3000怪物:" + monster.getId() + " 正常范围:" + (int) SkillRange + " 计算范围:" + (int) range); if (range > SkillRange * 2.0 && ((Integer) Start.ConfigValuesMap.get("全屏检测")).intValue() > 0) { player.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER_BAN, "超大攻击范围,技能:" + attack.skill + "(" + SkillFactory.getName(attack.skill) + ")\u3000怪物:" + monster.getId() + " 正常范围:" + (int) SkillRange + " 计算范围:" + (int) range); } return; } if (player.getBuffedValue(MapleBuffStat.PICKPOCKET) != null) { switch (attack.skill) { case 0: case 4001334: case 4201005: case 4211002: case 4211004: case 4221003: case 4221007: { handlePickPocket(player, monster, oned2); break; } } } final MapleStatEffect ds = player.getStatForBuff(MapleBuffStat.DARKSIGHT); if (ds != null && ds.getSourceId() != 9001004 && (ds.getSourceId() != 4330001 || !ds.makeChanceResult())) { player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT); } final MapleStatEffect wd = player.getStatForBuff(MapleBuffStat.WIND_WALK); if (wd != null && player.getJob() >= 1300 && player.getJob() <= 1312) { player.cancelEffectFromBuffStat(MapleBuffStat.WIND_WALK); } if (newtotDamageToOneMonster <= 0L) { continue; } final tzjc t = new tzjc(); newtotDamageToOneMonster = t.star_damage(player, newtotDamageToOneMonster, monster); if (attack.skill != 1221011) { long newDamage = 0L; newtotDamageToOneMonster = TWgetNewtotDamageToOneMonster(attack, player, newtotDamageToOneMonster, monster); monster.damage(player, newtotDamageToOneMonster, true, attack.skill); if (monster.getHp() > 0) { long hp = monster.getHp(); long mobMaxHp = monster.getMobMaxHp(); double percentage = ((double) hp / mobMaxHp) * 100; // 显式转换为浮点数并计算百分比‌:ml-citation{ref="1,3" data="citationList"} String result = String.format("%.2f%%", percentage); double l = (double) hp / mobMaxHp; player.dropMessage(-1, "当前怪物血量为:" +hp +" "+result); } } else { monster.damage(player, monster.getStats().isBoss() ? 500000L : (monster.getHp() - 1L), true, attack.skill); } if (monster.isBuffed(MonsterStatus.WEAPON_DAMAGE_REFLECT)) { player.addHP(-(7000 + Randomizer.nextInt(8000))); } if (stats.hpRecoverProp > 0 && Randomizer.nextInt(100) <= stats.hpRecoverProp) { player.healHP(stats.hpRecover); } if (stats.mpRecoverProp > 0 && Randomizer.nextInt(100) <= stats.mpRecoverProp) { player.healMP(stats.mpRecover); } if (player.getBuffedValue(MapleBuffStat.COMBO_DRAIN) != null) { stats.setHp(stats.getHp() + (int) Math.min(monster.getMobMaxHp(), (long) Math.min((int) ((double) totDamage * (double) player.getStatForBuff(MapleBuffStat.COMBO_DRAIN).getX() / 100.0), stats.getMaxHp() / 2)), true); } final int[] array; final int[] skillsl = array = new int[]{4120005, 4220005, 14110004}; final int length = array.length; int k = 0; while (k < length) { final int i = array[k]; final ISkill skill = SkillFactory.getSkill(i); if (player.getSkillLevel(skill) > 0) { final MapleStatEffect venomEffect = skill.getEffect((int) player.getSkillLevel(skill)); if (venomEffect.makeChanceResult()) { monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.POISON, Integer.valueOf(1), i, null, false), true, (long) venomEffect.getDuration(), monster.getStats().isBoss(), venomEffect); break; } break; } else { ++k; } } switch (attack.skill) { case 4101005: case 5111004: case 15111001: { final int getHP = (int) Math.min(monster.getMobMaxHp(), (long) Math.min((int) ((double) totDamage * (double) theSkill.getEffect((int) player.getSkillLevel(theSkill)).getX() / 100.0), stats.getMaxHp() / 2)); stats.setHp(stats.getHp() + getHP, true); break; } case 5211006: case 5220011: { player.setLinkMid(monster.getObjectId()); break; } case 1311005: { final int remainingHP = stats.getHp() - totDamage * ((effect != null) ? effect.getX() : 0) / 100; stats.setHp((remainingHP > 1) ? remainingHP : 1); break; } case 4001002: case 4001334: case 4001344: case 4111005: case 4121007: case 4201005: case 4211002: case 4211004: case 4221001: case 4221007: case 14001002: case 14001004: case 14111002: case 14111005: { if (player.hasBuffedValue(MapleBuffStat.WK_CHARGE) && !monster.getStats().isBoss()) { final MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.WK_CHARGE); if (eff != null) { monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.SPEED, Integer.valueOf(eff.getX()), eff.getSourceId(), null, false), false, (long) (eff.getY() * 1000), monster.getStats().isBoss(), eff); } } if (player.hasBuffedValue(MapleBuffStat.BODY_PRESSURE) && !monster.getStats().isBoss()) { final MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.BODY_PRESSURE); if (eff != null && eff.makeChanceResult() && !monster.isBuffed(MonsterStatus.NEUTRALISE)) { monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.NEUTRALISE, Integer.valueOf(1), eff.getSourceId(), null, false), false, (long) (eff.getX() * 1000), monster.getStats().isBoss(), eff); } } final int[] array2; final int[] skills = array2 = new int[]{4120005, 4220005, 14110004}; k = array2.length; int l = 0; while (l < k) { final int j = array2[l]; final ISkill skill2 = SkillFactory.getSkill(j); if (player.getSkillLevel(skill2) > 0) { final MapleStatEffect venomEffect2 = skill2.getEffect((int) player.getSkillLevel(skill2)); if (venomEffect2.makeChanceResult()) { monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.POISON, Integer.valueOf(1), j, null, false), true, (long) venomEffect2.getDuration(), monster.getStats().isBoss(), venomEffect2); break; } break; } else { ++l; } } break; } case 4201004: { monster.handleSteal(player); break; } case 21000002: case 21100001: case 21100002: case 21100004: case 21110002: case 21110003: case 21110004: case 21110006: case 21110007: case 21110008: case 21120002: case 21120005: case 21120006: case 21120009: case 21120010: { if (player.getBuffedValue(MapleBuffStat.WK_CHARGE) != null && !monster.getStats().isBoss()) { final MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.WK_CHARGE); if (eff != null) { monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.SPEED, Integer.valueOf(eff.getX()), eff.getSourceId(), null, false), false, (long) (eff.getY() * 1000), monster.getStats().isBoss(), eff); } } if (player.getBuffedValue(MapleBuffStat.BODY_PRESSURE) == null || monster.getStats().isBoss()) { break; } final MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.BODY_PRESSURE); if (eff != null && eff.makeChanceResult() && !monster.isBuffed(MonsterStatus.NEUTRALISE)) { monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.NEUTRALISE, Integer.valueOf(1), eff.getSourceId(), null, false), false, (long) (eff.getX() * 1000), true, eff); break; } break; } } if (totDamageToOneMonster > 0) { final IItem weapon_ = player.getInventory(MapleInventoryType.EQUIPPED).getItem((short) (-11)); if (weapon_ != null) { final MonsterStatus stat = GameConstants.getStatFromWeapon(weapon_.getItemId()); if (stat != null && Randomizer.nextInt(100) < GameConstants.getStatChance()) { final MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(stat, Integer.valueOf(GameConstants.getXForStat(stat)), GameConstants.getSkillForStat(stat), null, false); monster.applyStatus(player, monsterStatusEffect, false, 10000L, monster.getStats().isBoss(), null); } } if (player.hasBuffedValue(MapleBuffStat.BLIND)) { final MapleStatEffect eff2 = player.getStatForBuff(MapleBuffStat.BLIND); if (eff2 != null && eff2.makeChanceResult()) { final MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.ACC, Integer.valueOf(eff2.getX()), eff2.getSourceId(), null, false); monster.applyStatus(player, monsterStatusEffect, false, (long) (eff2.getY() * 1000), monster.getStats().isBoss(), eff2); } } if (player.hasBuffedValue(MapleBuffStat.HAMSTRING)) { final MapleStatEffect eff2 = player.getStatForBuff(MapleBuffStat.HAMSTRING); if (eff2 != null && eff2.makeChanceResult()) { final MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.SPEED, Integer.valueOf(eff2.getX()), 3121007, null, false); monster.applyStatus(player, monsterStatusEffect, false, (long) (eff2.getY() * 1000), monster.getStats().isBoss(), eff2); } } if (player.getJob() == 121) { ISkill skill3 = SkillFactory.getSkill(1211006); if (player.isBuffFrom(MapleBuffStat.WK_CHARGE, skill3)) { final MapleStatEffect eff3 = skill3.getEffect((int) player.getSkillLevel(skill3)); final MonsterStatusEffect monsterStatusEffect2 = new MonsterStatusEffect(MonsterStatus.FREEZE, Integer.valueOf(1), skill3.getId(), null, false); monster.applyStatus(player, monsterStatusEffect2, false, (long) (eff3.getY() * 2000), monster.getStats().isBoss(), eff3); } skill3 = SkillFactory.getSkill(1211005); if (player.isBuffFrom(MapleBuffStat.WK_CHARGE, skill3)) { final MapleStatEffect eff3 = skill3.getEffect((int) player.getSkillLevel(skill3)); final MonsterStatusEffect monsterStatusEffect2 = new MonsterStatusEffect(MonsterStatus.FREEZE, Integer.valueOf(1), skill3.getId(), null, false); monster.applyStatus(player, monsterStatusEffect2, false, (long) (eff3.getY() * 2000), monster.getStats().isBoss(), eff3); } } } if (effect == null || effect.getMonsterStati().size() <= 0 || !effect.makeChanceResult()) { continue; } for (final Entry z : effect.getMonsterStati().entrySet()) { monster.applyStatus(player, new MonsterStatusEffect((MonsterStatus) z.getKey(), (Integer) z.getValue(), theSkill.getId(), null, false), effect.isPoison(), (long) effect.getDuration(), monster.getStats().isBoss(), effect); } } } if (effect != null && attack.skill != 0 && (attack.targets > 0 || (attack.skill != 4331003 && attack.skill != 4341002)) && attack.skill != 21101003 && attack.skill != 5110001 && attack.skill != 15100004 && attack.skill != 11101002 && attack.skill != 13101002 && attack.skill != 14111006) { effect.applyTo(player, attack.position); } if (attack.skill == 14111006) { effect.applyTo(player, attack.positionxy); } if (totDamage > 1) { final CheatTracker tracker = player.getCheatTracker(); tracker.setAttacksWithoutHit(true); if (tracker.getAttacksWithoutHit() > 50) { tracker.registerOffense(CheatingOffense.ATTACK_WITHOUT_GETTING_HIT, Integer.toString(tracker.getAttacksWithoutHit())); } } } private static long TWgetNewtotDamageToOneMonster(AttackInfo attack, MapleCharacter player, long newtotDamageToOneMonster, MapleMonster monster) { newtotDamageToOneMonster += 额外伤害(player, newtotDamageToOneMonster, monster, true); //计算段数和倍率 double[] 额外段数 = 额外段数(player, monster, true, attack.skill); double[] 额外伤害倍率 = 额外伤害倍率(player, newtotDamageToOneMonster, monster, true, attack.skill); String a = ""; String b = ""; String c = ""; String d = ""; String e = ""; //获得未减伤之前的真实伤害 long 额外真伤 = 额外真伤(player, newtotDamageToOneMonster, monster, true, attack.skill); long v = 0; if (额外段数[0] > 0.0) { v = (long) (newtotDamageToOneMonster * (额外段数[0] * 额外段数[1]) / attack.hits); newtotDamageToOneMonster += (long) v; } if (额外伤害倍率[0] > 0.0) { newtotDamageToOneMonster += newtotDamageToOneMonster * (额外伤害倍率[0] / 100.0); a = "伤害加成 #b" + (int) 额外伤害倍率[0] + "%#k"; } if (额外段数[0] > 0.0) { b = "额外段伤 #b" + (int) 额外段数[0] + "段#k"; String s = convertNumber(v); c = "段伤伤害 #b" + s + "#k"; } if (额外真伤 > 0) { String s = convertNumber(额外真伤); d = "切割伤害 #b" + s + "#k"; } newtotDamageToOneMonster = 伤害减伤(monster.getId(), newtotDamageToOneMonster); //将计算完减伤之后的伤害加上真实伤害 newtotDamageToOneMonster += 额外真伤; String s2 = convertNumber(newtotDamageToOneMonster); e = "伤害统计 #r" + s2 + "#k"; int length = e.length(); if (!a.isEmpty()) { a = String.format("%-" + length + "s", a) ; } if (!b.isEmpty()) { b = String.format("%-" + (length) + "s", b) ; } if (!c.isEmpty()) { c = String.format("%-" + length + "s", c) ; } if (!d.isEmpty()) { d = String.format("%-" + length + "s", d) ; } int targetWidth = e.length()+6; // 目标显示宽度(半角字符数) String f = ""; String[] strs = {a, b, c, d, e}; for (String s : strs) { if (s.isEmpty())continue; int currentWidth = getDisplayWidth(s); int spacesNeeded = (currentWidth >= targetWidth) ? 0 : (targetWidth - currentWidth); // 填充空格并截断‌:ml-citation{ref="2,3" data="citationList"} s= String.format("%s%" + spacesNeeded + "s", s, "").substring(0, Math.min(s.length() + spacesNeeded, s.length() + targetWidth)) ; s+="\r\n"; f +=s; // System.out.println("|" + aligned + "|"); } e = a + b + c + d + e; player.showInstruction(f, 130, 10); return newtotDamageToOneMonster; } public static final void applyAttackMagic(final AttackInfo attack, final ISkill theSkill, final MapleCharacter player, final MapleStatEffect effect) { if (!player.isAlive()) { player.getCheatTracker().registerOffense(CheatingOffense.ATTACKING_WHILE_DEAD); return; } if (attack.real) { player.getCheatTracker().checkAttack(attack.skill, attack.lastAttackTickCount); } int last = (effect.getAttackCount() > effect.getBulletCount()) ? effect.getAttackCount() : effect.getBulletCount(); boolean mirror_fix = false; if (player.getJob() >= 411 && player.getJob() <= 412) { mirror_fix = true; } if (player.getJob() >= 1400 && player.getJob() <= 1412) { mirror_fix = true; } if (attack.skill == 11101004) { last = 2; } if (attack.skill == 15111007) { last = 3; } last = 技能段数(attack.skill); if (mirror_fix || player.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) { last *= 2; } if (attack.hits > last) { if (!player.hasGmLevel(1)) { Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 攻击次数异常已自动封锁。 玩家攻击次数 " + (int) attack.hits + " 服务端判断正常攻击次数 " + last + " 技能ID " + attack.skill)); FileoutputUtil.logToFile("logs/Hack/Ban/技能攻击次数.txt", "\r\n" + FileoutputUtil.NowTime() + "玩家2: " + player.getName() + "(" + (int) player.getLevel() + ") 技能代码: " + attack.skill + " 技能等级: " + player.getSkillLevel(attack.skill) + " 攻击次数 : " + (int) attack.hits + " 正常攻击次数 :" + last); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "技能攻击次数异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } final String reason = "使用违法程式练功"; if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为" + reason + "而被管理员永久停权。")); } return; } player.dropMessage("攻击次数异常攻击次数 " + (int) attack.hits + " 服务端判断正常攻击次数 " + last + " 技能ID " + attack.skill); } int CheckCount = effect.getMobCount(); CheckCount = 技能个数(attack.skill); if (attack.targets > CheckCount) { if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/打怪数量异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家2: " + player.getName() + "(" + (int) player.getLevel() + ") 技能代码: " + attack.skill + " 技能等级: " + player.getSkillLevel(effect.getSourceId()) + " 封包怪物量 : " + (int) attack.targets + " 服务端怪物量 :" + CheckCount); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 攻击怪物数量异常。 封包怪物量 " + (int) attack.targets + " 服务端怪物量 " + CheckCount + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "打怪数量异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } final String reason2 = "使用违法程式练功"; if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为" + reason2 + "而被管理员永久停权。")); } return; } player.dropMessage("打怪数量异常,技能代码: " + attack.skill + " 封包怪物量 : " + (int) attack.targets + " 服务端怪物量 :" + CheckCount); } if (attack.hits > 0 && attack.targets > 0 && !player.getStat().checkEquipDurabilitys(player, -1)) { player.dropMessage(5, "An item has run out of durability but has no inventory room to go to."); return; } if (GameConstants.isMulungSkill(attack.skill)) { if (player.getMapId() / 10000 != 92502) { return; } player.mulungEnergyModify(false); } if (GameConstants.isPyramidSkill(attack.skill)) { if (player.getMapId() / 1000000 != 926) { return; } if (player.getPyramidSubway() == null || !player.getPyramidSubway().onSkillUse(player)) { return; } } final PlayerStats stats = player.getStat(); //最终伤害值 double maxDamagePerHit; if (attack.skill == 1000 || attack.skill == 10001000 || attack.skill == 20001000 || attack.skill == 20011000 || attack.skill == 30001000) { maxDamagePerHit = 40.0; } else if (GameConstants.isPyramidSkill(attack.skill)) { maxDamagePerHit = 1.0; } else { final double v75 = (double) effect.getMatk() * 0.058; maxDamagePerHit = (double) stats.getTotalMagic() * ((double) stats.getInt() * 0.5 + v75 * v75 + (double) effect.getMatk() * 3.3) / 100.0; } maxDamagePerHit *= 1.04; final Element element = (player.getBuffedValue(MapleBuffStat.ELEMENT_RESET) != null) ? Element.NEUTRAL : theSkill.getElement(); double MaxDamagePerHit = 0.0; int totDamage = 0; final int CriticalDamage = stats.passive_sharpeye_percent(); final ISkill eaterSkill = SkillFactory.getSkill(GameConstants.getMPEaterForJob((int) player.getJob())); final int eaterLevel = player.getSkillLevel(eaterSkill); final MapleMap map = player.getMap(); if (map.getId() == 990010000) { MaplePvp.doPvP(player, map, attack); } int 循环 = 0; for (final AttackPair oned : attack.allDamage) { final MapleMonster monster = map.getMonsterByOid(oned.objectid); ++循环; if (monster != null) { final boolean Tempest = monster.getStatusSourceID(MonsterStatus.FREEZE) == 21120006 && !monster.getStats().isBoss(); int totDamageToOneMonster = 0; long newtotDamageToOneMonster = 0L; final MapleMonsterStats monsterstats = monster.getStats(); final int fixeddmg = monsterstats.getFixedDamage(); MaxDamagePerHit = calculateMaxMagicDamagePerHit(player, theSkill, monster, monsterstats, stats, element, Integer.valueOf(CriticalDamage), maxDamagePerHit); byte overallAttackCount = 0; for (final Pair eachde : oned.attack) { Integer eachd = (Integer) eachde.left; ++overallAttackCount; if (!GameConstants.isElseSkill(attack.skill)) { if (GameConstants.Novice_Skill(attack.skill) && eachd.intValue() > 40) { if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家2<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 最高伤害: 40 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss()); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 40 本次伤害 " + eachd + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "伤害异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); } return; } player.dropMessage("[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 40 本次伤害 " + eachd + " 技能ID " + attack.skill); } int atk = 2140000001; if (eachd.intValue() < 0) { if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 伤害过低导致越界 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss()); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 伤害过低导致越界本次伤害 " + eachd + " 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "伤害异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); } return; } player.dropMessage("[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 伤害过低导致越界本次伤害 " + eachd + " 技能ID " + attack.skill); } if (!GameConstants.isAran((int) player.getJob()) && player.getLevel() > 10) { boolean ban = false; if (((Integer) Start.ConfigValuesMap.get("伤害检测")).intValue() > 0) { atk = ((Integer) Start.ConfigValuesMap.get("伤害上限")).intValue(); } if (eachd.intValue() >= atk && (double) eachd.intValue() > Math.ceil(maxDamagePerHit * 1.2)) { ban = true; } if ((long) eachd.intValue() == monster.getMobMaxHp()) { ban = false; } if (ban) { boolean apple = false; if (player.getBuffSource(MapleBuffStat.WATK) == 2022179 || player.getBuffSource(MapleBuffStat.MATK) == 2022179 || player.getBuffSource(MapleBuffStat.WDEF) == 2022179) { apple = true; } if (!player.hasGmLevel(1)) { FileoutputUtil.logToFile("logs/Hack/Ban/伤害异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家2<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 最高伤害: " + atk + " 本次伤害 :" + eachd + " 预计伤害: " + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss() + " 紫色蘋果: " + apple); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 " + atk + " 本次伤害 " + eachd + " 技能ID " + attack.skill + "预计伤害: " + (int) maxDamagePerHit)); if (((Integer) Start.ConfigValuesMap.get("封停IP")).intValue() > 0) { player.ban(player.getName() + "伤害异常", true, true, false); } if (((Integer) Start.ConfigValuesMap.get("封停MAC")).intValue() > 0) { player.getClient().banMacs(); } if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { player.getClient().getSession().close(); } if (((Integer) Start.ConfigValuesMap.get("全服通告")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为伤害异常而被管理员永久停权。")); } return; } player.dropMessage("[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 伤害异常。 最高伤害 " + atk + " 本次伤害 " + eachd + " 技能ID " + attack.skill + "预计伤害: " + (int) maxDamagePerHit); } } } if (fixeddmg != -1) { eachd = Integer.valueOf(monsterstats.getOnlyNoramlAttack() ? 0 : fixeddmg); } else if (monsterstats.getOnlyNoramlAttack()) { eachd = Integer.valueOf(0); } else if (!player.isGM() && ((Integer) Start.ConfigValuesMap.get("伤害修正")).intValue() > 0) { if (!Tempest) { if (!monster.isBuffed(MonsterStatus.DAMAGE_IMMUNITY) && !monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY) && !monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT)) { if ((double) eachd.intValue() > maxDamagePerHit) { player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE, "[伤害: " + eachd + ", 预期: " + maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 使用的技能: " + attack.skill + "]"); if (attack.real) { player.getCheatTracker().checkSameDamage(eachd.intValue(), maxDamagePerHit); } if ((double) eachd.intValue() > MaxDamagePerHit * 2.0) { eachd = Integer.valueOf((int) (MaxDamagePerHit * 2.0)); player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_MAGIC_2, "[伤害: " + eachd + ", 预期: " + maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 使用的技能: " + attack.skill + "]"); if (eachd.intValue() >= 10000 && ServerConfig.LOG_DAMAGE) { FileoutputUtil.logToFile("Logs/hack/伤害计算/魔法伤害计算修正_" + attack.skill + ".txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家: " + player.getName() + "(" + (int) player.getLevel() + ") 职业: " + (int) player.getJob() + " 怪物:" + monster.getId() + " 封包伤害 :" + eachd + " 预计伤害 :" + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss(), false, false); player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_MAGIC_2, "[伤害: " + eachd + ", 预期: " + maxDamagePerHit + ", 怪物: " + monster.getId() + "] [职业: " + (int) player.getJob() + ", 等级: " + (int) player.getLevel() + ", 使用的技能: " + attack.skill + "]"); return; } } } } else if ((double) eachd.intValue() > maxDamagePerHit) { eachd = Integer.valueOf((int) maxDamagePerHit); if ((double) eachd.intValue() > MaxDamagePerHit * 2.0 && maxDamagePerHit != 1.0 && ServerConfig.LOG_DAMAGE) { FileoutputUtil.logToFile("Logs/hack/伤害计算/魔法伤害计算修正_" + attack.skill + ".txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家: " + player.getName() + "(" + (int) player.getLevel() + ") 职业: " + (int) player.getJob() + " 怪物:" + monster.getId() + " 封包伤害 :" + eachd + " 预计伤害 :" + (int) maxDamagePerHit + "是否为BOSS: " + monster.getStats().isBoss(), false, false); } } } } totDamageToOneMonster += eachd.intValue(); newtotDamageToOneMonster += (long) eachd.intValue(); } totDamage += totDamageToOneMonster; player.checkMonsterAggro(monster); final double range = player.getPosition().distanceSq((Point2D) monster.getPosition()); double SkillRange = GameConstants.getAttackRange(player, effect, attack); if (((Integer) Start.ConfigValuesMap.get("重置技能范围开关")).intValue() > 0) { SkillRange = (double) ((Integer) Start.ConfigValuesMap.get("重置技能总范围")).intValue(); } if (player.getDebugMessage() && range > SkillRange) { player.dropMessage("技能[" + attack.skill + "] 预计范围: " + (int) SkillRange + " 实際范围: " + (int) range); } if (range > SkillRange && !player.inBossMap() && attack.skill != 5221004 && attack.skill != 21120006) { player.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER, "攻击范围异常,技能:" + attack.skill + "(" + SkillFactory.getName(attack.skill) + ")\u3000正常范围:" + (int) SkillRange + " 计算范围:" + (int) range); if (range > SkillRange * 2.0 && ((Integer) Start.ConfigValuesMap.get("全屏检测")).intValue() > 0) { player.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER_BAN, "超大攻击范围,技能:" + attack.skill + "(" + SkillFactory.getName(attack.skill) + ")\u3000怪物:" + monster.getId() + " 正常范围:" + (int) SkillRange + " 计算范围:" + (int) range); } return; } if (attack.skill == 2301002 && !monsterstats.getUndead()) { player.getCheatTracker().registerOffense(CheatingOffense.HEAL_ATTACKING_UNDEAD); FileoutputUtil.logToFile("logs/Hack/Ban/技能异常.txt", "\r\n " + FileoutputUtil.NowTime() + " 玩家2<" + (int) player.getLevel() + ">: " + player.getName() + " 怪物 " + monster.getId() + " 地图: " + player.getMapId() + " 技能代码: " + attack.skill + " 使用群体治愈攻击非不死系怪物"); Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM 密语系统] " + player.getName() + " (等级 " + (int) player.getLevel() + ") 技能异常。 使用群体治愈攻击非不死系怪物 技能ID " + attack.skill)); if (((Integer) Start.ConfigValuesMap.get("封停账号")).intValue() > 0) { Broadcast.broadcastMessage(MaplePacketCreator.serverNotice(6, "[封锁系统] " + player.getName() + " 因为技能异常而被管理员永久停权。")); player.ban(player.getName() + "修改WZ", true, true, false); player.getClient().getSession().close(); return; } } if (newtotDamageToOneMonster <= 0L) { continue; } final tzjc t = new tzjc(); long newDamage = 0L; newtotDamageToOneMonster = TWgetNewtotDamageToOneMonster(attack, player, newtotDamageToOneMonster, monster); monster.damage(player, newtotDamageToOneMonster, true, attack.skill); if (monster.getHp() > 0) { player.dropMessage(-1, "当前怪物血量为: " + monster.getHp()); } if (monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT)) { player.addHP(-(7000 + Randomizer.nextInt(8000))); } switch (attack.skill) { case 2221003: { monster.setTempEffectiveness(Element.FIRE, (long) theSkill.getEffect((int) player.getSkillLevel(theSkill)).getDuration()); break; } case 2121003: { monster.setTempEffectiveness(Element.ICE, (long) theSkill.getEffect((int) player.getSkillLevel(theSkill)).getDuration()); break; } } if (effect.getMonsterStati().size() >= 0 && effect.makeChanceResult()) { for (final Entry z : effect.getMonsterStati().entrySet()) { monster.applyStatus(player, new MonsterStatusEffect((MonsterStatus) z.getKey(), (Integer) z.getValue(), theSkill.getId(), null, false), effect.isPoison(), (long) effect.getDuration(), monster.getStats().isBoss(), effect); } } if (eaterLevel <= 0) { continue; } eaterSkill.getEffect(eaterLevel).applyPassive(player, (MapleMapObject) monster); } } if (attack.skill != 2301002) { effect.applyTo(player); } if (totDamage > 1) { final CheatTracker tracker = player.getCheatTracker(); tracker.setAttacksWithoutHit(true); if (tracker.getAttacksWithoutHit() > 1000) { tracker.registerOffense(CheatingOffense.ATTACK_WITHOUT_GETTING_HIT, Integer.toString(tracker.getAttacksWithoutHit())); } } } private static double calculateMaxMagicDamagePerHit(final MapleCharacter chr, final ISkill skill, final MapleMonster monster, final MapleMonsterStats mobstats, final PlayerStats stats, final Element elem, final Integer sharpEye, final double maxDamagePerMonster) { final int dLevel = Math.max(mobstats.getLevel() - chr.getLevel(), 0); final int Accuracy = (int) (Math.floor((double) stats.getTotalInt() / 10.0) + Math.floor((double) stats.getTotalLuk() / 10.0)); final int MinAccuracy = mobstats.getEva() * (dLevel * 2 + 51) / 120; if (MinAccuracy > Accuracy && skill.getId() != 1000 && skill.getId() != 10001000 && skill.getId() != 20001000 && skill.getId() != 20011000 && skill.getId() != 30001000 && !GameConstants.isPyramidSkill(skill.getId())) { return 0.0; } double elemMaxDamagePerMob = 0.0; switch (monster.getEffectiveness(elem)) { case IMMUNE: { elemMaxDamagePerMob = 1.0; break; } case NORMAL: { elemMaxDamagePerMob = ElementalStaffAttackBonus(elem, maxDamagePerMonster, stats); break; } case WEAK: { elemMaxDamagePerMob = ElementalStaffAttackBonus(elem, maxDamagePerMonster * 1.5, stats); break; } case STRONG: { elemMaxDamagePerMob = ElementalStaffAttackBonus(elem, maxDamagePerMonster * 0.5, stats); break; } default: { throw new RuntimeException("Unknown enum constant"); } } elemMaxDamagePerMob -= (double) mobstats.getMagicDefense() * 0.5; elemMaxDamagePerMob += elemMaxDamagePerMob / 100.0 * (double) sharpEye.intValue(); if (skill.getId() == 21120006) { elemMaxDamagePerMob *= 15.0; } if (skill.getId() == 2211006) { elemMaxDamagePerMob *= 2.0; } elemMaxDamagePerMob += elemMaxDamagePerMob * (mobstats.isBoss() ? stats.bossdam_r : stats.dam_r) / 100.0; switch (skill.getId()) { case 1000: case 10001000: case 20001000: { elemMaxDamagePerMob = 40.0; break; } case 1020: case 10001020: case 20001020: { elemMaxDamagePerMob = 1.0; break; } } if (elemMaxDamagePerMob <= 500000.0) { if (elemMaxDamagePerMob < 0.0) { elemMaxDamagePerMob = 1.0; } } return elemMaxDamagePerMob; } private static final double ElementalStaffAttackBonus(final Element elem, final double elemMaxDamagePerMob, final PlayerStats stats) { switch (elem) { case FIRE: { return elemMaxDamagePerMob / 100.0 * (double) stats.element_fire; } case ICE: { return elemMaxDamagePerMob / 100.0 * (double) stats.element_ice; } case LIGHTING: { return elemMaxDamagePerMob / 100.0 * (double) stats.element_light; } case POISON: { return elemMaxDamagePerMob / 100.0 * (double) stats.element_psn; } default: { return elemMaxDamagePerMob / 100.0 * (double) stats.def; } } } private static void handlePickPocket(final MapleCharacter player, final MapleMonster mob, final AttackPair oned) { final int maxmeso = player.getBuffedValue(MapleBuffStat.PICKPOCKET).intValue(); final ISkill skill = SkillFactory.getSkill(4211003); final MapleStatEffect s = skill.getEffect((int) player.getSkillLevel(skill)); for (final Pair eachde : oned.attack) { final Integer eachd = (Integer) eachde.left; if (s.makeChanceResult()) { player.getMap().spawnMesoDrop(Math.min((int) Math.max((double) eachd.intValue() / 20000.0 * (double) maxmeso, 1.0), maxmeso), new Point((int) (mob.getTruePosition().getX() + (double) Randomizer.nextInt(100) - 50.0), (int) mob.getTruePosition().getY()), (MapleMapObject) mob, player, false, (byte) 0); } } } private static double calculateMaxWeaponDamagePerHit(final MapleCharacter player, final MapleMonster monster, final AttackInfo attack, final ISkill theSkill, final MapleStatEffect attackEffect, double maximumDamageToMonster, final Integer CriticalDamagePercent) { if (player.getMapId() / 1000000 == 914) { return 5.0E8; } final List elements = (List) new ArrayList(); boolean defined = false; if (theSkill != null) { elements.add(theSkill.getElement()); if (monster.getStatusSourceID(MonsterStatus.FREEZE) == 21120006) { defined = true; } switch (theSkill.getId()) { case 3001004: case 3221001: { defined = true; break; } case 1000: case 10001000: case 20001000: case 20011000: case 30001000: { maximumDamageToMonster = 40.0; defined = true; break; } case 1020: case 10001020: case 20001020: case 20011020: case 30001020: { maximumDamageToMonster = 1.0; defined = true; break; } case 3221007: { maximumDamageToMonster = (double) (monster.getStats().isBoss() ? 500000L : monster.getMobMaxHp()); defined = true; break; } case 1221011: { maximumDamageToMonster = (double) (monster.getStats().isBoss() ? 500000L : (monster.getHp() - 1L)); defined = true; break; } case 4211006: { maximumDamageToMonster = (double) (monster.getStats().isBoss() ? 500000L : monster.getMobMaxHp()); defined = true; break; } case 1009: case 10001009: case 20001009: case 20011009: case 30001009: { defined = true; maximumDamageToMonster = (double) (monster.getStats().isBoss() ? (monster.getMobMaxHp() / 30L * 100L) : monster.getMobMaxHp()); break; } case 3211006: { if (monster.getStatusSourceID(MonsterStatus.FREEZE) == 3211003) { defined = true; maximumDamageToMonster = (double) monster.getHp(); break; } break; } case 5121007: { maximumDamageToMonster *= 2.8; break; } case 1111008: case 1121006: case 1311001: case 1311006: case 4201005: { maximumDamageToMonster *= 3.0; break; } case 1001004: case 1121008: case 4221001: { maximumDamageToMonster *= 2.5; break; } case 1001005: case 1311004: case 3121004: { maximumDamageToMonster *= 2.0; break; } } } if (MapleJob.is战神((int) player.getJob())) { maximumDamageToMonster *= 2.0; } else if (MapleJob.is拳霸((int) player.getJob())) { maximumDamageToMonster *= 1.1; } if (player.getBuffedValue(MapleBuffStat.WK_CHARGE) != null) { final int chargeSkillId = player.getBuffSource(MapleBuffStat.WK_CHARGE); switch (chargeSkillId) { case 1211003: case 1211004: { elements.add(Element.FIRE); break; } case 1211005: case 1211006: case 21111005: { elements.add(Element.ICE); break; } case 1211007: case 1211008: case 15101006: { elements.add(Element.LIGHTING); break; } case 1221003: case 1221004: case 11111007: { elements.add(Element.HOLY); break; } case 12101005: { elements.clear(); break; } } } if (player.getBuffedValue(MapleBuffStat.LIGHTNING_CHARGE) != null) { elements.add(Element.LIGHTING); } double elementalMaxDamagePerMonster = maximumDamageToMonster; if (elements.size() > 0) { double elementalEffect = 0.0; switch (attack.skill) { case 3111003: case 3211003: { elementalEffect = (double) attackEffect.getX() / 200.0; break; } default: { elementalEffect = 0.5; break; } } for (final Element element : elements) { switch (monster.getEffectiveness(element)) { case IMMUNE: { elementalMaxDamagePerMonster = 1.0; continue; } case WEAK: { elementalMaxDamagePerMonster *= 1.0 + elementalEffect; continue; } case STRONG: { elementalMaxDamagePerMonster *= 1.0 - elementalEffect; continue; } } } } final short moblevel = monster.getStats().getLevel(); final short d = (short) ((moblevel > player.getLevel()) ? ((short) (moblevel - player.getLevel())) : 0); elementalMaxDamagePerMonster = elementalMaxDamagePerMonster * (1.0 - 0.01 * (double) d) - (double) monster.getStats().getPhysicalDefense() * 0.5; elementalMaxDamagePerMonster += elementalMaxDamagePerMonster / 100.0 * (double) CriticalDamagePercent.intValue(); if (theSkill != null && theSkill.isChargeSkill() && player.getKeyDownSkill_Time() == 0L && theSkill.getId() != 4111005) { return 0.0; } final MapleStatEffect homing = player.getStatForBuff(MapleBuffStat.HOMING_BEACON); if (homing != null && player.getLinkMid() == monster.getObjectId() && homing.getSourceId() == 5220011) { elementalMaxDamagePerMonster += elementalMaxDamagePerMonster * (double) homing.getX(); } final PlayerStats stat = player.getStat(); elementalMaxDamagePerMonster += elementalMaxDamagePerMonster * (monster.getStats().isBoss() ? (stat.bossdam_r * 2.0) : stat.dam_r) / 100.0; switch (monster.getId()) { case 1110101: { elementalMaxDamagePerMonster *= 2.0; break; } } if (player.getDebugMessage()) { player.dropMessage("[伤害计算]属性伤害:" + (int) Math.ceil(elementalMaxDamagePerMonster) + " BOSS伤害:" + (int) Math.ceil((monster.getStats().isBoss() ? player.getStat().bossdam_r : player.getStat().dam_r) - 100.0) + "%"); } if (elementalMaxDamagePerMonster > 500000.0) { if (!defined) { } } else if (elementalMaxDamagePerMonster < 0.0) { elementalMaxDamagePerMonster = 1.0; } return elementalMaxDamagePerMonster; } public static final AttackInfo DivideAttack(final AttackInfo attack, final int rate) { attack.real = false; for (final AttackPair p : attack.allDamage) { if (p.attack != null) { for (final Pair eachd : p.attack) { long 伤害 = 0L; 伤害 = (long) ((Integer) eachd.left).intValue() * (long) (((Integer) Start.ConfigValuesMap.get("克隆基础伤害")).intValue() + rate) / 100L; if (伤害 >= 21000000000L) { eachd.left = Integer.valueOf(2100000000); } else { eachd.left = Integer.valueOf((int) 伤害); } } } } return attack; } public static final AttackInfo Modify_AttackCrit(final AttackInfo attack, final MapleCharacter chr, final int type) { final int criticalRate = chr.getStat().passive_sharpeye_rate(); final boolean shadow = (type == 2 && chr.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) || (type == 1 && chr.getBuffedValue(MapleBuffStat.MIRROR_IMAGE) != null); if (attack.skill != 4211006 && attack.skill != 3211003 && attack.skill != 4111004 && (criticalRate > 0 || attack.skill == 4221001 || attack.skill == 3221007)) { for (final AttackPair attackPair : attack.allDamage) { if (attackPair.attack != null) { int hit = 0; final int midAtt = attackPair.attack.size() / 2; final List> eachd_copy = new ArrayList(attackPair.attack); for (final Pair eachd : attackPair.attack) { ++hit; if (!((Boolean) eachd.right).booleanValue()) { if (attack.skill == 4221001) { eachd.right = Boolean.valueOf(hit == 4 && Randomizer.nextInt(100) < 90); } else if (attack.skill == 3221007 || ((Integer) eachd.left).intValue() > 199999) { eachd.right = Boolean.valueOf(true); } else if (shadow && hit > midAtt) { eachd.right = (eachd_copy.get(hit - 1 - midAtt)).right; } else { eachd.right = Boolean.valueOf(Randomizer.nextInt(100) < criticalRate); } (eachd_copy.get(hit - 1)).right = eachd.right; } } } } } return attack; } public static final AttackInfo parseDmgMa(final LittleEndianAccessor lea, final MapleCharacter chr) { final AttackInfo ret = new AttackInfo(); lea.skip(1); lea.skip(8); ret.tbyte = lea.readByte(); ret.targets = (byte) (ret.tbyte >>> 4 & 0xF); ret.hits = (byte) (ret.tbyte & 0xF); lea.skip(8); ret.skill = lea.readInt(); lea.skip(12); switch (ret.skill) { case 2121001: case 2221001: case 2321001: case 22121000: case 22151001: { ret.charge = lea.readInt(); break; } default: { ret.charge = -1; break; } } lea.skip(1); ret.unk = 0; ret.display = lea.readByte(); ret.animation = lea.readByte(); lea.skip(1); ret.speed = lea.readByte(); if (ret.display == 2126 && ret.speed == 5 && ret.skill == 0) { Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[系统警告] ID " + chr.getId() + " " + chr.getName() + " 疑似使用路飞霸气。 ")); } ret.lastAttackTickCount = lea.readInt(); ret.allDamage = (List) new ArrayList(); for (int i = 0; i < ret.targets; ++i) { final int oid = lea.readInt(); lea.skip(14); final List> allDamageNumbers = (List>) new ArrayList(); for (int j = 0; j < ret.hits; ++j) { int damage = lea.readInt(); int 系统最大破功 = 199999; if (((Integer) Start.ConfigValuesMap.get("伤害突破开关")).intValue() > 0) { 系统最大破功 = ((Integer) Start.ConfigValuesMap.get("突破上线")).intValue(); } int maxdamage = 0; if (((Integer) Start.ConfigValuesMap.get("装备卡破功开关")).intValue() > 0) { int 破攻值 = 0; int 装备破攻值 = 0; 破攻值 = 装备破功(chr); 装备破攻值 = 装备基础破功(chr); maxdamage = 装备破攻值 + 破攻值; } if (((Integer) Start.ConfigValuesMap.get("装备卡破功开关")).intValue() > 0 && damage > maxdamage) { damage = maxdamage; } if (((Integer) Start.ConfigValuesMap.get("表单卡破功开关")).intValue() > 0) { maxdamage = (int) chr.getLimitBreak(); } if (((Integer) Start.ConfigValuesMap.get("表单卡破功开关")).intValue() > 0 && damage > maxdamage) { damage = maxdamage; } if (damage > 系统最大破功) { damage = 系统最大破功; } if ((ret.skill == 3221007 || ret.skill == 4221001) && damage >= 199999) { damage = 199999; } if (chr.isGM() && ((Integer) Start.ConfigValuesMap.get("GM固伤开关")).intValue() > 0) { damage = GM伤害(chr); } if (((Integer) Start.ConfigValuesMap.get("所有显示开关")).intValue() > 0 && ((Integer) Start.ConfigValuesMap.get("突破显示开关")).intValue() > 0) { chr.dropMessage(-1, "客户端传输实际伤害1: " + damage); } allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false))); } lea.skip(4); ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers)); } ret.position = lea.readPos(); return ret; } public static final AttackInfo parseDmgM(final LittleEndianAccessor lea, final MapleCharacter chr) { final AttackInfo ret = new AttackInfo(); lea.skip(1); lea.skip(8); ret.tbyte = lea.readByte(); ret.targets = (byte) (ret.tbyte >>> 4 & 0xF); ret.hits = (byte) (ret.tbyte & 0xF); lea.skip(8); ret.skill = lea.readInt(); lea.skip(12); switch (ret.skill) { case 5101004: case 5201002: case 14111006: case 15101003: { ret.charge = lea.readInt(); break; } default: { ret.charge = 0; break; } } ret.unk = lea.readByte(); ret.display = lea.readByte(); ret.animation = lea.readByte(); lea.skip(1); ret.speed = lea.readByte(); if (ret.display == 2126 && ret.speed == 5 && ret.skill == 0) { Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[系统警告] ID " + chr.getId() + " " + chr.getName() + " 疑似使用路飞霸气。 ")); } ret.lastAttackTickCount = lea.readInt(); ret.allDamage = (List) new ArrayList(); if (ret.skill == 4211006) { return parseExplosionAttack(lea, ret); } for (int i = 0; i < ret.targets; ++i) { final int oid = lea.readInt(); lea.skip(14); final List> allDamageNumbers = (List>) new ArrayList(); for (int j = 0; j < ret.hits; ++j) { int damage = lea.readInt(); int 系统最大破功 = 199999; if (((Integer) Start.ConfigValuesMap.get("伤害突破开关")).intValue() > 0) { 系统最大破功 = ((Integer) Start.ConfigValuesMap.get("突破上线")).intValue(); } int maxdamage = 0; if (((Integer) Start.ConfigValuesMap.get("装备卡破功开关")).intValue() > 0) { int 破攻值 = 0; int 装备破攻值 = 0; 破攻值 = 装备破功(chr); 装备破攻值 = 装备基础破功(chr); maxdamage = 装备破攻值 + 破攻值; } if (((Integer) Start.ConfigValuesMap.get("装备卡破功开关")).intValue() > 0 && damage > maxdamage) { damage = maxdamage; } if (((Integer) Start.ConfigValuesMap.get("表单卡破功开关")).intValue() > 0) { maxdamage = (int) chr.getLimitBreak(); } if (((Integer) Start.ConfigValuesMap.get("表单卡破功开关")).intValue() > 0 && damage > maxdamage) { damage = maxdamage; } if (damage > 系统最大破功) { damage = 系统最大破功; } if ((ret.skill == 3221007 || ret.skill == 4221001) && damage >= 199999) { damage = 199999; } if (chr.isGM() && ((Integer) Start.ConfigValuesMap.get("GM固伤开关")).intValue() > 0) { damage = GM伤害(chr); } if (((Integer) Start.ConfigValuesMap.get("所有显示开关")).intValue() > 0 && ((Integer) Start.ConfigValuesMap.get("突破显示开关")).intValue() > 0) { chr.dropMessage(-1, "客户端传输实际伤害2: " + damage); } allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false))); } lea.skip(4); ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers)); } ret.position = lea.readPos(); if (ret.skill == 14111006) { ret.positionxy = lea.readPos(); } return ret; } public static final AttackInfo parseDmgR(final LittleEndianAccessor lea, final MapleCharacter chr) { final AttackInfo ret = new AttackInfo(); lea.skip(1); lea.skip(8); ret.tbyte = lea.readByte(); ret.targets = (byte) (ret.tbyte >>> 4 & 0xF); ret.hits = (byte) (ret.tbyte & 0xF); lea.skip(8); ret.skill = lea.readInt(); lea.skip(12); switch (ret.skill) { case 3121004: case 3221001: case 5221004: case 13111002: { lea.skip(4); break; } } ret.charge = -1; ret.unk = lea.readByte(); ret.display = lea.readByte(); ret.animation = lea.readByte(); lea.skip(1); ret.speed = lea.readByte(); if (ret.display == 2126 && ret.speed == 5 && ret.skill == 0) { Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[系统警告] ID " + chr.getId() + " " + chr.getName() + " 疑似使用路飞霸气。 ")); } ret.lastAttackTickCount = lea.readInt(); ret.slot = (byte) lea.readShort(); ret.csstar = (byte) lea.readShort(); ret.AOE = lea.readByte(); ret.allDamage = (List) new ArrayList(); for (int i = 0; i < ret.targets; ++i) { final int oid = lea.readInt(); lea.skip(14); final List> allDamageNumbers = (List>) new ArrayList(); for (int j = 0; j < ret.hits; ++j) { int damage = lea.readInt(); int 系统最大破功 = 199999; if (((Integer) Start.ConfigValuesMap.get("伤害突破开关")).intValue() > 0) { 系统最大破功 = ((Integer) Start.ConfigValuesMap.get("突破上线")).intValue(); } int maxdamage = 0; if (((Integer) Start.ConfigValuesMap.get("装备卡破功开关")).intValue() > 0) { int 破攻值 = 0; int 装备破攻值 = 0; 破攻值 = 装备破功(chr); 装备破攻值 = 装备基础破功(chr); maxdamage = 装备破攻值 + 破攻值; } if (((Integer) Start.ConfigValuesMap.get("装备卡破功开关")).intValue() > 0 && damage > maxdamage) { damage = maxdamage; } if (((Integer) Start.ConfigValuesMap.get("表单卡破功开关")).intValue() > 0) { maxdamage = (int) chr.getLimitBreak(); } if (((Integer) Start.ConfigValuesMap.get("表单卡破功开关")).intValue() > 0 && damage > maxdamage) { damage = maxdamage; } if (damage > 系统最大破功) { damage = 系统最大破功; } if ((ret.skill == 3221007 || ret.skill == 4221001) && damage >= 199999) { damage = 199999; } if (chr.isGM() && ((Integer) Start.ConfigValuesMap.get("GM固伤开关")).intValue() > 0) { damage = GM伤害(chr); } if (((Integer) Start.ConfigValuesMap.get("所有显示开关")).intValue() > 0 && ((Integer) Start.ConfigValuesMap.get("突破显示开关")).intValue() > 0) { chr.dropMessage(-1, "客户端传输实际伤害3: " + damage); } allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false))); } lea.skip(4); ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers)); } lea.skip(4); ret.position = lea.readPos(); return ret; } public static final AttackInfo parseExplosionAttack(final LittleEndianAccessor lea, final AttackInfo ret) { if (ret.hits == 0) { lea.skip(4); final byte bullets = lea.readByte(); for (int j = 0; j < bullets; ++j) { ret.allDamage.add(new AttackPair(lea.readInt(), null)); lea.skip(1); } lea.skip(2); return ret; } for (int i = 0; i < ret.targets; ++i) { final int oid = lea.readInt(); lea.skip(12); final byte bullets2 = lea.readByte(); final List> allDamageNumbers = (List>) new ArrayList(); for (int k = 0; k < bullets2; ++k) { allDamageNumbers.add(new Pair(Integer.valueOf(lea.readInt()), Boolean.valueOf(false))); } ret.allDamage.add(new AttackPair(oid, allDamageNumbers)); lea.skip(4); } lea.skip(4); final byte bullets = lea.readByte(); for (int j = 0; j < bullets; ++j) { ret.allDamage.add(new AttackPair(lea.readInt(), null)); lea.skip(1); } lea.skip(2); return ret; } public static int GM伤害(final MapleCharacter chr) { final int 伤害 = ((Integer) Start.ConfigValuesMap.get("GM固伤伤害")).intValue(); return 伤害; } public static int 装备破功(final MapleCharacter chr) { int 破攻值 = 0; int 破攻系数 = 0; final IItem 装备 = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) (-11)); if (装备 != null && 装备 instanceof Equip) { 破攻系数 = MapleItemInformationProvider.getInstance().getHands((Equip) 装备); 破攻值 = 破攻系数 * 10000; } return 破攻值; } public static int 技能段数(final int skill) { int last = 99; if (((Integer) Start.ConfigValuesMap.get("段数检测")).intValue() > 0) { for (int a = 0; a < Start.SkillType.size(); ++a) { if (skill == ((SkillType) Start.SkillType.get(a)).getSkillId()) { last = ((SkillType) Start.SkillType.get(a)).getAttackCount(); break; } } } return last; } public static int 技能个数(final int skill) { int last = 99; if (((Integer) Start.ConfigValuesMap.get("个数检测")).intValue() > 0) { for (int a = 0; a < Start.SkillType.size(); ++a) { if (skill == ((SkillType) Start.SkillType.get(a)).getSkillId()) { last = ((SkillType) Start.SkillType.get(a)).getMobCount(); break; } } } return last; } public static long 伤害减伤(final int mobid, final long damage) { long 数值 = 0L; if (((Integer) Start.ConfigValuesMap.get("怪物减伤开关")).intValue() > 0) { 数值 = (long) Math.floor((double) (damage / (long) getMobRedDam(mobid))); } else { 数值 = damage; } return 数值; } public static double[] 额外段数(final MapleCharacter play, final MapleMonster monster, boolean mag, int skillId) { double Magnification = 0.0; if (Start.ConfigValuesJson == null) return new double[]{0.0, 0.0}; Magnification = play.getDD(); Double ddxs = Start.ConfigValuesJson.getJSONObject("ddxs").getDouble(String.valueOf(skillId)); if (ddxs == null) { ddxs = 1.0; } if (Magnification == 0) { return new double[]{0.0, 0.0}; } return new double[]{Magnification, ddxs}; } public static double[] 额外伤害倍率(final MapleCharacter play, long damage, final MapleMonster monster, boolean mag, int skillId) { double Magnification = 0.0; Magnification = play.getDB(); Double ddxs = Start.ConfigValuesJson.getJSONObject("dbxs").getDouble(String.valueOf(skillId)); if (ddxs == null) { ddxs = 1.0; } return new double[]{Magnification, ddxs}; } public static long 额外真伤(final MapleCharacter play, long damage, final MapleMonster monster, boolean mag, int skillId) { double Magnification = 0.0; Magnification = play.getQG(); Double qgxs = Start.ConfigValuesJson.getJSONObject("qgxs").getDouble(String.valueOf(skillId)); if (qgxs == null) { qgxs = 1.0; } if (Magnification > 0) { return (long) ((Magnification * qgxs)); } else { return 0; } } public static long 额外伤害(final MapleCharacter play, final long damage, final MapleMonster monster, boolean mag) { long 数值 = 0L; try { if (damage >= Integer.MAX_VALUE) { if (mag) 数值 = (long) (play.getStat().calculateMaxBaseDamage(play.getStat().getTotalMagic(), play.getStat().getTotalWatk()) * 14); else 数值 = (long) (play.getStat().calculateMaxBaseDamage(play.getStat().getTotalMagic(), play.getStat().getTotalWatk()) * 525); } if (((Integer) Start.ConfigValuesMap.get("自定义伤害加成开关")).intValue() < 1) { return 数值; } if (damage >= (long) ((Integer) Start.ConfigValuesMap.get("伤害高于次数值")).intValue() || (((Integer) Start.ConfigValuesMap.get("道具加成自定义伤害开关")).intValue() > 0 && play.getItemQuantity(((Integer) Start.ConfigValuesMap.get("自定义伤害加成道具代码")).intValue(), false) > 0)) { 数值 = (long) play.getComStr() * (long) ((Integer) Start.ConfigValuesMap.get("自定义力量加成比例")).intValue() + (long) play.getComDex() * (long) ((Integer) Start.ConfigValuesMap.get("自定义敏捷加成比例")).intValue() + (long) play.getComInt() * (long) ((Integer) Start.ConfigValuesMap.get("自定义智力加成比例")).intValue() + (long) play.getComLuk() * (long) ((Integer) Start.ConfigValuesMap.get("自定义运气加成比例")).intValue() + (long) play.getComWatk() * (long) ((Integer) Start.ConfigValuesMap.get("自定义物攻加成比例")).intValue() + (long) play.getComMatk() * (long) ((Integer) Start.ConfigValuesMap.get("自定义魔攻加成比例")).intValue() + (long) play.getComWdef() * (long) ((Integer) Start.ConfigValuesMap.get("自定义物防加成比例")).intValue() + (long) play.getComMdef() * (long) ((Integer) Start.ConfigValuesMap.get("自定义魔防加成比例")).intValue() + (long) play.getComHp() * (long) ((Integer) Start.ConfigValuesMap.get("自定义血量加成比例")).intValue() + (long) play.getComMp() * (long) ((Integer) Start.ConfigValuesMap.get("自定义魔量加成比例")).intValue(); } if (((Integer) Start.ConfigValuesMap.get("扣除21E伤害")).intValue() > 0) { 数值 -= 21474836470L; } if (((Integer) Start.ConfigValuesMap.get("自定义伤害气泡显示")).intValue() > 0) { play.showInstruction("【#r额外伤害 → " + 数值 + "#k】", 240, 10); } if (((Integer) Start.ConfigValuesMap.get("自定义伤害黄字喇叭显示")).intValue() > 0) { play.dropMessage(-1, "【额外伤害 →" + 数值 + "】"); } if (数值 > 0) { play.dropMessage(-1, "【额外伤害 →" + 数值 + "】"); play.getMap().broadcastMessage(MobPacket.damageMonster(monster.getObjectId(), (long) (int) 数值)); } } catch (Exception e) { FileoutputUtil.outError("logs/额外伤害异常.txt", (Throwable) e); return 数值; } return 数值; } public static int 装备基础破功(final MapleCharacter chr) { int 破攻值1 = 0; int 装备等级 = 0; final IItem 装备 = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) (-11)); if (装备 != null) { 装备等级 = MapleItemInformationProvider.getInstance().getReqLevel(装备.getItemId()); } if (装备等级 < 120) { 破攻值1 = 199999; } else if (装备等级 >= 120 && 装备等级 < 125) { 破攻值1 = 249999; } else if (装备等级 >= 125 && 装备等级 < 130) { 破攻值1 = 299999; } else if (装备等级 >= 130 && 装备等级 < 135) { 破攻值1 = 349999; } else if (装备等级 >= 135 && 装备等级 < 140) { 破攻值1 = 399999; } else if (装备等级 >= 140 && 装备等级 < 145) { 破攻值1 = 449999; } else if (装备等级 >= 145 && 装备等级 < 150) { 破攻值1 = 499999; } else if (装备等级 >= 150 && 装备等级 < 160) { 破攻值1 = 549999; } else if (装备等级 >= 160 && 装备等级 < 180) { 破攻值1 = 599999; } else if (装备等级 >= 180 && 装备等级 < 200) { 破攻值1 = 699999; } else if (装备等级 >= 200 && 装备等级 < 230) { 破攻值1 = 799999; } else if (装备等级 >= 230 && 装备等级 <= 255) { 破攻值1 = 999999; } return 破攻值1; } public static void readMobRedDam() { DamageParse.MobRedDam.clear(); Connection con = null; PreparedStatement ps = null; ResultSet rs = null; try { con = (Connection) DBConPool.getInstance().getDataSource().getConnection(); ps = con.prepareStatement("SELECT * FROM mobreddam"); rs = ps.executeQuery(); while (rs.next()) { final Integer sn = Integer.valueOf(rs.getInt("mobid")); final Integer numb = Integer.valueOf(rs.getInt("numb")); DamageParse.MobRedDam.put(sn, numb); } rs.close(); ps.close(); } catch (Exception e) { FileoutputUtil.outError("logs/减伤读取异常.txt", (Throwable) e); DBConPool.cleanUP(rs, ps, con); e.printStackTrace(); } finally { DBConPool.cleanUP(rs, ps, con); } } public static int getMobRedDam(final int mobid) { if (DamageParse.MobRedDam.get(Integer.valueOf(mobid)) != null) { return ((Integer) DamageParse.MobRedDam.get(Integer.valueOf(mobid))).intValue(); } return 1; } static { readMobRedDam(); } // 计算字符串显示宽度(全角字符算2,半角算1) private static int getDisplayWidth(String s) { return s.codePoints().map(c -> (c <= 255) ? 1 : 2).sum(); } public static String convertNumber(long number) { if (number < 10000) { // 数字小于 10000,直接返回原数字 return String.valueOf(number); } else if (number < 100000000) { // 数字大于等于 10000 且小于 1 亿,转换为以“万”为单位 double result = (double) number / 10000; return String.format("%.0f万", result); } else if (number < 10000000000000000L) { // 数字大于等于 1 亿 且小于 1 京,转换为以“亿”为单位 double result = (double) number / 100000000; return String.format("%.0f亿", result); } else { // 数字大于等于 1 京,转换为以“京”为单位 double result = (double) number / 10000000000000000L; return String.format("%.0f京", result); } } }