package handling.channel.handler;
import clientside.MapleBuffStat;
import clientside.MapleCharacter;
import clientside.PlayerStats;
import clientside.Skill;
import clientside.SkillFactory;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.status.MonsterStatus;
import client.status.MonsterStatusEffect;
import constants.GameConstants;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import server.MaplePVP;
import server.MapleStatEffect;
import server.Randomizer;
import server.life.Element;
import server.life.ElementalEffectiveness;
import server.life.MapleMonster;
import server.life.MapleMonsterStats;
import server.maps.MapleMap;
import server.maps.MapleMapItem;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import tools.AttackPair;
import tools.Pair;
import tools.data.LittleEndianAccessor;
import tools.packet.CField;
import tools.packet.CWvsContext;
public class DamageParse {
public static void applyAttack(AttackInfo attack, Skill theSkill, MapleCharacter player, int attackCount, double maxDamagePerMonster, MapleStatEffect effect, AttackType attack_type) {
if (!player.isAlive()) {
return;
}
if (attack.skill != 0) {
if (effect == null) {
player.getClient().getSession().write(CWvsContext.enableActions());
return;
}
if (GameConstants.isMulungSkill(attack.skill)) {
if (player.getMapId() / 10000 != 92502) {
return;
}
if (player.getMulungEnergy() < 10000) {
return;
}
player.mulung_EnergyModify(false);
} else if (GameConstants.isPyramidSkill(attack.skill)) {
if (player.getMapId() / 1000000 != 926) {
return;
}
if ((player.getPyramidSubway() != null) && (player.getPyramidSubway().onSkillUse(player)));
} else if (GameConstants.isInflationSkill(attack.skill)) {
if (player.getBuffedValue(MapleBuffStat.GIANT_POTION) != null);
}
}
if (player.getClient().getChannelServer().isAdminOnly()) {
player.dropMessage(-1, new StringBuilder().append("Animation: ").append(Integer.toHexString((attack.display & 0x8000) != 0 ? attack.display - 32768 : attack.display)).toString());
}
boolean useAttackCount = (attack.skill != 4211006) && (attack.skill != 3221007) && (attack.skill != 23121003) && ((attack.skill != 1311001) || (player.getJob() != 132)) && (attack.skill != 3211006);
if ((attack.hits > 0) && (attack.targets > 0)) {
if (!player.getStat().checkEquipDurabilitys(player, -1)) {
player.dropMessage(5, "An item has run out of durability but has no inventory room to go to.");
return;
}
}
int totDamage = 0;
MapleMap map = player.getMap();
if (attack.skill == 4211006) {
for (AttackPair oned : attack.allDamage) {
if (oned.attack == null) {
MapleMapObject mapobject = map.getMapObject(oned.objectid, MapleMapObjectType.ITEM);
if (mapobject != null) {
MapleMapItem mapitem = (MapleMapItem) mapobject;
mapitem.getLock().lock();
try {
if (mapitem.getMeso() > 0) {
if (mapitem.isPickedUp()) {
return;
}
map.removeMapObject(mapitem);
map.broadcastMessage(CField.explodeDrop(mapitem.getObjectId()));
return;
}
} finally {
mapitem.getLock().unlock();
}
} else {
return;
}
}
}
}
int totDamageToOneMonster = 0;
long hpMob = 0L;
PlayerStats stats = player.getStat();
int CriticalDamage = stats.passive_sharpeye_percent();
int ShdowPartnerAttackPercentage = 0;
if ((attack_type == AttackType.RANGED_WITH_SHADOWPARTNER) || (attack_type == AttackType.NON_RANGED_WITH_MIRROR)) {
MapleStatEffect shadowPartnerEffect = player.getStatForBuff(MapleBuffStat.SHADOWPARTNER);
if (shadowPartnerEffect != null) {
ShdowPartnerAttackPercentage += shadowPartnerEffect.getX();
}
attackCount /= 2;
}
ShdowPartnerAttackPercentage *= (CriticalDamage + 100) / 100;
if (attack.skill == 4221001) {
ShdowPartnerAttackPercentage *= 10;
}
double maxDamagePerHit = 0.0D;
for (AttackPair oned : attack.allDamage) {
MapleMonster monster = map.getMonsterByOid(oned.objectid);
if ((monster != null) && (monster.getLinkCID() <= 0)) {
if (GameConstants.isWindArcher(player.getJob())) {
int percent = 0, count = 0, skillid = 0, type = 0;
if (player.getSkillLevel(SkillFactory.getSkill(13120003)) > 0) {
if (Randomizer.nextInt(100) < 85) {
skillid = 13120003;
type = 1;
} else {
skillid = 13120010;
type = 1;
}
count = Randomizer.rand(1, 5);
percent = 20;
} else if (player.getSkillLevel(SkillFactory.getSkill(13110022)) > 0) {
if (Randomizer.nextInt(100) < 90) {
skillid = 13110022;
type = 1;
} else {
skillid = 13110027;
type = 1;
}
count = Randomizer.rand(1, 4);
percent = 10;
} else if (player.getSkillLevel(SkillFactory.getSkill(13100022)) > 0) {
if (Randomizer.nextInt(100) < 95) {
skillid = 13100022;
type = 1;
} else {
skillid = 13100027;
type = 1;
}
count = Randomizer.rand(1, 3);
percent = 5;
}
for (AttackPair at : attack.allDamage) {
monster = map.getMonsterByOid(at.objectid);
if (Randomizer.nextInt(100) < percent) {
if (monster != null) {
player.getMap().broadcastMessage(player, CField.TrifleWorm(player.getId(), skillid, count, monster.getObjectId(), type), false);
player.send(CField.TrifleWorm(player.getId(), skillid, count, monster.getObjectId(), type));
}
}
}
}
totDamageToOneMonster = 0;
hpMob = monster.getMobMaxHp();
MapleMonsterStats monsterstats = monster.getStats();
int fixeddmg = monsterstats.getFixedDamage();
boolean Tempest = (monster.getStatusSourceID(MonsterStatus.FREEZE) == 21120006) || (attack.skill == 21120006) || (attack.skill == 1221011);
if ((!Tempest) && (!player.isGM())) {
if (((player.getJob() >= 3200) && (player.getJob() <= 3212) && (!monster.isBuffed(MonsterStatus.DAMAGE_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT))) || (attack.skill == 3221007) || (attack.skill == 23121003) || (((player.getJob() < 3200) || (player.getJob() > 3212)) && (!monster.isBuffed(MonsterStatus.DAMAGE_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.WEAPON_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.WEAPON_DAMAGE_REFLECT)))) {
maxDamagePerHit = CalculateMaxWeaponDamagePerHit(player, monster, attack, theSkill, effect, maxDamagePerMonster, Integer.valueOf(CriticalDamage));
} else {
maxDamagePerHit = 1.0D;
}
}
byte overallAttackCount = 0;
int criticals = 0;
for (Pair eachde : oned.attack) {
Integer eachd = (Integer) eachde.left;
overallAttackCount = (byte) (overallAttackCount + 1);
if (((Boolean) eachde.right).booleanValue()) {
criticals++;
}
if ((useAttackCount) && (overallAttackCount - 1 == attackCount)) {
maxDamagePerHit = maxDamagePerHit / 100.0D * (ShdowPartnerAttackPercentage * (monsterstats.isBoss() ? stats.bossdam_r : stats.dam_r) / 100.0D);
}
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()) {
if (Tempest) {
if (eachd.intValue() > monster.getMobMaxHp()) {
eachd = Integer.valueOf((int) Math.min(monster.getMobMaxHp(), 2147483647L));
}
} else if (((player.getJob() >= 3200) && (player.getJob() <= 3212) && (!monster.isBuffed(MonsterStatus.DAMAGE_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT))) || (attack.skill == 23121003) || (((player.getJob() < 3200) || (player.getJob() > 3212)) && (!monster.isBuffed(MonsterStatus.DAMAGE_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.WEAPON_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.WEAPON_DAMAGE_REFLECT)))) {
} else if (eachd.intValue() > maxDamagePerHit) {
eachd = Integer.valueOf((int) maxDamagePerHit);
}
}
if (player == null) {
return;
}
totDamageToOneMonster += eachd.intValue();
if (((eachd.intValue() == 0) || (monster.getId() == 9700021)) && (player.getPyramidSubway() != null)) {
player.getPyramidSubway().onMiss(player);
}
}
totDamage += totDamageToOneMonster;
player.checkMonsterAggro(monster);
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, oned);
}
}
if ((totDamageToOneMonster > 0) || (attack.skill == 1221011) || (attack.skill == 21120006)) {
if (GameConstants.isDemon(player.getJob())) {
player.handleForceGain(monster.getObjectId(), attack.skill);
}
if ((GameConstants.isPhantom(player.getJob())) && (attack.skill != 24120002) && (attack.skill != 24100003)) {
player.handleCardStack();
}
if (GameConstants.kaiser(player.getJob())) {
player.handleKaiserCombo();
}
if (attack.skill != 1221011) {
monster.damage(player, totDamageToOneMonster, true, attack.skill);
} 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)));
}
player.onAttack(monster.getMobMaxHp(), monster.getMobMaxMp(), attack.skill, monster.getObjectId(), totDamage, 0);
switch (attack.skill) {
case 4001002:
case 4001334:
case 4001344:
case 4111005:
case 4121007:
case 4201005:
case 4211002:
case 4221001:
case 4221007:
case 4301001:
case 4311002:
case 4311003:
case 4331000:
case 4331004:
case 4331005:
case 4331006:
case 4341002:
case 4341004:
case 4341005:
case 4341009:
case 14001004:
case 14111002:
case 14111005:
int[] skills = {4120005, 4220005, 4340001, 14110004};
for (int i : skills) {
Skill skill = SkillFactory.getSkill(i);
if (player.getTotalSkillLevel(skill) > 0) {
MapleStatEffect venomEffect = skill.getEffect(player.getTotalSkillLevel(skill));
if (!venomEffect.makeChanceResult()) {
break;
}
monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.POISON, Integer.valueOf(1), i, null, false), true, venomEffect.getDuration(), true, venomEffect);
break;
}
}
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())) {
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, eff.getY() * 1000, true, eff);
}
}
if ((player.getBuffedValue(MapleBuffStat.BODY_PRESSURE) != null) && (!monster.getStats().isBoss())) {
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, eff.getX() * 1000, true, eff);
}
}
break;
}
int randomDMG = 0;
if (GameConstants.demonAvenger(player.getJob())) {
randomDMG = player.getDamage2();
}
monster.damage(player, randomDMG, true, attack.skill);
if (player.getshowdamage() == 1) {
player.dropMessage(5, new StringBuilder().append("You have done ").append(randomDMG).append(" extra RB damage! (disable/enable this with @dmgnotice)").toString());
}
} else {
if (player.getDamage() > 2147483647L) {
long randomDMG = player.getDamage();
monster.damage(player, monster.getMobMaxHp(), true, attack.skill);
if (player.getshowdamage() == 1) {
player.dropMessage(5, new StringBuilder().append("You have done ").append(randomDMG).append(" extra RB damage! (disable/enable this with @dmgnotice)").toString());
}
}
if (totDamageToOneMonster > 0) {
Item weapon_ = player.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -11);
if (weapon_ != null) {
MonsterStatus stat = GameConstants.getStatFromWeapon(weapon_.getItemId());
if ((stat != null) && (Randomizer.nextInt(100) < GameConstants.getStatChance())) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(stat, Integer.valueOf(GameConstants.getXForStat(stat)), GameConstants.getSkillForStat(stat), null, false);
monster.applyStatus(player, monsterStatusEffect, false, 10000L, false, null);
}
}
if (player.getBuffedValue(MapleBuffStat.BLIND) != null) {
MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.BLIND);
if ((eff != null) && (eff.makeChanceResult())) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.ACC, Integer.valueOf(eff.getX()), eff.getSourceId(), null, false);
monster.applyStatus(player, monsterStatusEffect, false, eff.getY() * 1000, true, eff);
}
}
if (player.getBuffedValue(MapleBuffStat.HAMSTRING) != null) {
MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.HAMSTRING);
if ((eff != null) && (eff.makeChanceResult())) {
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.SPEED, Integer.valueOf(eff.getX()), 3121007, null, false);
monster.applyStatus(player, monsterStatusEffect, false, eff.getY() * 1000, true, eff);
}
}
if ((player.getJob() == 121) || (player.getJob() == 122)) {
Skill skill = SkillFactory.getSkill(1211006);
if (player.isBuffFrom(MapleBuffStat.WK_CHARGE, skill)) {
MapleStatEffect eff = skill.getEffect(player.getTotalSkillLevel(skill));
MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.FREEZE, Integer.valueOf(1), skill.getId(), null, false);
monster.applyStatus(player, monsterStatusEffect, false, eff.getY() * 2000, true, eff);
}
}
}
if ((effect != null) && (effect.getMonsterStati().size() > 0) && (effect.makeChanceResult())) {
for (Map.Entry z : effect.getMonsterStati().entrySet()) {
monster.applyStatus(player, new MonsterStatusEffect((MonsterStatus) z.getKey(), (Integer) z.getValue(), theSkill.getId(), null, false), effect.isPoison(), effect.getDuration(), true, effect);
}
}
}
}
}
MapleMonster monster;
if ((attack.skill == 4331003) && ((hpMob <= 0L) || (totDamageToOneMonster < hpMob))) {
return;
}
if ((hpMob > 0L) && (totDamageToOneMonster > 0)) {
player.afterAttack(attack.targets, attack.hits, attack.skill);
}
if ((attack.skill != 0) && ((attack.targets > 0) || ((attack.skill != 4331003) && (attack.skill != 4341002)) && attack.skill != 4341052) && (!GameConstants.isNoDelaySkill(attack.skill))) {
effect.applyTo(player, attack.position);
}
if (attack.skill != 2301002 && attack.skill != 4201004 && attack.skill != 1111008 && player.getMapId() == 100000000 && player.getClient().getChannel() == 9) {//checks
MaplePVP.doPvP(player, map, attack);
}
}
public static final void applyAttackMagic(AttackInfo attack, Skill theSkill, MapleCharacter player, MapleStatEffect effect, double maxDamagePerHit) {
if (!player.isAlive()) {
return;
}
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;
}
if (player.getMulungEnergy() < 10000) {
return;
}
player.mulung_EnergyModify(false);
} else if (GameConstants.isPyramidSkill(attack.skill)) {
if (player.getMapId() / 1000000 != 926) {
return;
}
if ((player.getPyramidSubway() != null) && (player.getPyramidSubway().onSkillUse(player)));
} else if ((GameConstants.isInflationSkill(attack.skill)) && (player.getBuffedValue(MapleBuffStat.GIANT_POTION) == null)) {
return;
}
if (player.getClient().getChannelServer().isAdminOnly()) {
player.dropMessage(-1, new StringBuilder().append("Animation: ").append(Integer.toHexString((attack.display & 0x8000) != 0 ? attack.display - 32768 : attack.display)).toString());
}
PlayerStats stats = player.getStat();
Element element = player.getBuffedValue(MapleBuffStat.ELEMENT_RESET) != null ? Element.NEUTRAL : theSkill.getElement();
double MaxDamagePerHit = 0.0D;
int totDamage = 0;
int CriticalDamage = stats.passive_sharpeye_percent();
Skill eaterSkill = SkillFactory.getSkill(GameConstants.getMPEaterForJob(player.getJob()));
int eaterLevel = player.getTotalSkillLevel(eaterSkill);
MapleMap map = player.getMap();
for (AttackPair oned : attack.allDamage) {
MapleMonster monster = map.getMonsterByOid(oned.objectid);
if ((monster != null) && (monster.getLinkCID() <= 0)) {
boolean Tempest = (monster.getStatusSourceID(MonsterStatus.FREEZE) == 21120006) && (!monster.getStats().isBoss());
int totDamageToOneMonster = 0;
MapleMonsterStats monsterstats = monster.getStats();
int fixeddmg = monsterstats.getFixedDamage();
if ((!Tempest) && (!player.isGM())) {
if ((!monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT))) {
MaxDamagePerHit = CalculateMaxMagicDamagePerHit(player, theSkill, monster, monsterstats, stats, element, Integer.valueOf(CriticalDamage), maxDamagePerHit, effect);
} else {
MaxDamagePerHit = 1.0D;
}
}
byte overallAttackCount = 0;
for (Pair eachde : oned.attack) {
Integer eachd = (Integer) eachde.left;
overallAttackCount = (byte) (overallAttackCount + 1);
if (fixeddmg != -1) {
eachd = Integer.valueOf(monsterstats.getOnlyNoramlAttack() ? 0 : fixeddmg);
} else if (monsterstats.getOnlyNoramlAttack()) {
eachd = Integer.valueOf(0);
} else if (!player.isGM()) {
if (Tempest) {
if (eachd.intValue() > monster.getMobMaxHp()) {
eachd = Integer.valueOf((int) Math.min(monster.getMobMaxHp(), 2147483647L));
}
} else if ((!monster.isBuffed(MonsterStatus.MAGIC_IMMUNITY)) && (!monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT))) {
} else if (eachd.intValue() > MaxDamagePerHit) {
eachd = Integer.valueOf((int) MaxDamagePerHit);
}
}
totDamageToOneMonster += eachd.intValue();
}
int randomDMG = 0;
if (GameConstants.demonAvenger(player.getJob())) {
randomDMG = player.getDamage2();
}
monster.damage(player, randomDMG, true, attack.skill);
totDamage += totDamageToOneMonster;
player.checkMonsterAggro(monster);
if ((attack.skill == 2301002) && (!monsterstats.getUndead())) {
return;
}
if (GameConstants.isluminous(player.getJob())) {
player.handleLuminous(attack.skill);
}
monster.damage(player, totDamage, true, attack.skill);
} else if (player.getDamage() > 2147483647L) {
long randomDMG = player.getDamage();
monster.damage(player, monster.getMobMaxHp(), true, attack.skill);
if (player.getshowdamage() == 1) {
player.dropMessage(5, new StringBuilder().append("You have done ").append(randomDMG).append(" extra damage! (disable/enable this with @dmgnotice)").toString());
}
int totDamageToOneMonster1 = 0;
if (totDamageToOneMonster1 > 0) {
monster.damage(player, totDamageToOneMonster1, true, attack.skill);
if (monster.isBuffed(MonsterStatus.MAGIC_DAMAGE_REFLECT)) {
// player.addHP(-(7000 + Randomizer.nextInt(8000)));
}
if (player.getBuffedValue(MapleBuffStat.SLOW) != null) {
MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.SLOW);
if ((eff != null) && (eff.makeChanceResult()) && (!monster.isBuffed(MonsterStatus.SPEED))) {
monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.SPEED, Integer.valueOf(eff.getX()), eff.getSourceId(), null, false), false, eff.getY() * 1000, true, eff);
}
}
player.onAttack(monster.getMobMaxHp(), monster.getMobMaxMp(), attack.skill, monster.getObjectId(), totDamage, 0);
switch (attack.skill) {
case 2221003:
monster.setTempEffectiveness(Element.ICE, effect.getDuration());
break;
case 2121003:
monster.setTempEffectiveness(Element.FIRE, effect.getDuration());
}
if ((effect != null) && (effect.getMonsterStati().size() > 0) && (effect.makeChanceResult())) {
for (Map.Entry z : effect.getMonsterStati().entrySet()) {
monster.applyStatus(player, new MonsterStatusEffect((MonsterStatus) z.getKey(), (Integer) z.getValue(), theSkill.getId(), null, false), effect.isPoison(), effect.getDuration(), true, effect);
}
}
if (eaterLevel > 0) {
eaterSkill.getEffect(eaterLevel).applyPassive(player, monster);
}
}
}
if (attack.skill != 2301002 && attack.skill != 4201004 && attack.skill != 1111008 && player.getMapId() == 100000000 && player.getClient().getChannel() == 9) {//checks
MaplePVP.doPvP(player, map, attack);
}
if (attack.skill != 2301002) {
effect.applyTo(player);
}
}
}
private static final double CalculateMaxMagicDamagePerHit(MapleCharacter chr, Skill skill, MapleMonster monster, MapleMonsterStats mobstats, PlayerStats stats, Element elem, Integer sharpEye, double maxDamagePerMonster, MapleStatEffect attackEffect) {
int dLevel = Math.max(mobstats.getLevel() - chr.getLevel(), 0) * 2;
int HitRate = Math.min((int) Math.floor(Math.sqrt(stats.getAccuracy())) - (int) Math.floor(Math.sqrt(mobstats.getEva())) + 100, 100);
if (dLevel > HitRate) {
HitRate = dLevel;
}
HitRate -= dLevel;
if ((HitRate <= 0) && ((!GameConstants.isBeginnerJob(skill.getId() / 10000)) || (skill.getId() % 10000 != 1000))) {
return 0.0D;
}
int CritPercent = sharpEye.intValue();
ElementalEffectiveness ee = monster.getEffectiveness(elem);
double elemMaxDamagePerMob;
switch (ee) {
case IMMUNE:
elemMaxDamagePerMob = 1.0D;
break;
default:
elemMaxDamagePerMob = ElementalStaffAttackBonus(elem, maxDamagePerMonster * ee.getValue(), stats);
}
int MDRate = monster.getStats().getMDRate();
MonsterStatusEffect pdr = monster.getBuff(MonsterStatus.MDEF);
if (pdr != null) {
MDRate += pdr.getX().intValue();
}
elemMaxDamagePerMob -= elemMaxDamagePerMob * (Math.max(MDRate - stats.ignoreTargetDEF - attackEffect.getIgnoreMob(), 0) / 100.0D);
elemMaxDamagePerMob += elemMaxDamagePerMob / 100.0D * CritPercent;
elemMaxDamagePerMob *= (monster.getStats().isBoss() ? chr.getStat().bossdam_r : chr.getStat().dam_r) / 100.0D;
MonsterStatusEffect imprint = monster.getBuff(MonsterStatus.IMPRINT);
if (imprint != null) {
elemMaxDamagePerMob += elemMaxDamagePerMob * imprint.getX().intValue() / 100.0D;
}
elemMaxDamagePerMob += elemMaxDamagePerMob * chr.getDamageIncrease(monster.getObjectId()) / 100.0D;
if (GameConstants.isBeginnerJob(skill.getId() / 10000)) {
switch (skill.getId() % 10000) {
case 1000:
elemMaxDamagePerMob = 40.0D;
break;
case 1020:
elemMaxDamagePerMob = 1.0D;
break;
case 1009:
elemMaxDamagePerMob = monster.getStats().isBoss() ? monster.getMobMaxHp() / 30L * 100L : monster.getMobMaxHp();
}
}
switch (skill.getId()) {
case 32001000:
case 32101000:
case 32111002:
case 32121002:
elemMaxDamagePerMob *= 1.5D;
}
if (elemMaxDamagePerMob > 999999.0D) {
elemMaxDamagePerMob = 999999.0D;
} else if (elemMaxDamagePerMob <= 0.0D) {
elemMaxDamagePerMob = 1.0D;
}
return elemMaxDamagePerMob;
}
private static final double ElementalStaffAttackBonus(Element elem, double elemMaxDamagePerMob, PlayerStats stats) {
switch (elem) {
case FIRE:
return elemMaxDamagePerMob / 100.0D * (stats.element_fire + stats.getElementBoost(elem));
case ICE:
return elemMaxDamagePerMob / 100.0D * (stats.element_ice + stats.getElementBoost(elem));
case LIGHTING:
return elemMaxDamagePerMob / 100.0D * (stats.element_light + stats.getElementBoost(elem));
case POISON:
return elemMaxDamagePerMob / 100.0D * (stats.element_psn + stats.getElementBoost(elem));
}
return elemMaxDamagePerMob / 100.0D * (stats.def + stats.getElementBoost(elem));
}
private static void handlePickPocket(MapleCharacter player, MapleMonster mob, AttackPair oned) {
int maxmeso = player.getBuffedValue(MapleBuffStat.PICKPOCKET).intValue();
for (Pair eachde : oned.attack) {
Integer eachd = (Integer) eachde.left;
if ((player.getStat().pickRate >= 100) || (Randomizer.nextInt(99) < player.getStat().pickRate)) {
player.getMap().spawnMesoDrop(Math.min((int) Math.max(eachd.intValue() / 20000.0D * maxmeso, 1.0D), maxmeso), new Point((int) (mob.getTruePosition().getX() + Randomizer.nextInt(100) - 50.0D), (int) mob.getTruePosition().getY()), mob, player, false, (byte) 0);
}
}
}
private static double CalculateMaxWeaponDamagePerHit(MapleCharacter player, MapleMonster monster, AttackInfo attack, Skill theSkill, MapleStatEffect attackEffect, double maximumDamageToMonster, Integer CriticalDamagePercent) {
int dLevel = Math.max(monster.getStats().getLevel() - player.getLevel(), 0) * 2;
int HitRate = Math.min((int) Math.floor(Math.sqrt(player.getStat().getAccuracy())) - (int) Math.floor(Math.sqrt(monster.getStats().getEva())) + 100, 100);
if (dLevel > HitRate) {
HitRate = dLevel;
}
HitRate -= dLevel;
if ((HitRate <= 0) && ((!GameConstants.isBeginnerJob(attack.skill / 10000)) || (attack.skill % 10000 != 1000)) && (!GameConstants.isPyramidSkill(attack.skill)) && (!GameConstants.isMulungSkill(attack.skill)) && (!GameConstants.isInflationSkill(attack.skill))) {
return 0.0D;
}
if ((player.getMapId() / 1000000 == 914) || (player.getMapId() / 1000000 == 927)) {
return 999999.0D;
}
List<Element> elements = new ArrayList();
boolean defined = false;
int CritPercent = CriticalDamagePercent.intValue();
int PDRate = monster.getStats().getPDRate();
MonsterStatusEffect pdr = monster.getBuff(MonsterStatus.WDEF);
if (pdr != null) {
PDRate += pdr.getX().intValue();
}
if (theSkill != null) {
elements.add(theSkill.getElement());
if (GameConstants.isBeginnerJob(theSkill.getId() / 10000)) {
switch (theSkill.getId() % 10000) {
case 1000:
maximumDamageToMonster = 40.0D;
defined = true;
break;
case 1020:
maximumDamageToMonster = 1.0D;
defined = true;
break;
case 1009:
maximumDamageToMonster = monster.getStats().isBoss() ? monster.getMobMaxHp() / 30L * 100L : monster.getMobMaxHp();
defined = true;
}
}
switch (theSkill.getId()) {
case 1311005:
PDRate = monster.getStats().isBoss() ? PDRate : 0;
break;
case 3221001:
case 33101001:
maximumDamageToMonster *= attackEffect.getMobCount();
defined = true;
break;
case 3101005:
defined = true;
break;
case 32001000:
case 32101000:
case 32111002:
case 32121002:
maximumDamageToMonster *= 1.5D;
break;
case 1221009:
case 3221007:
case 4331003:
case 23121003:
if (!monster.getStats().isBoss()) {
maximumDamageToMonster = monster.getMobMaxHp();
defined = true;
}
break;
case 1221011:
case 21120006:
maximumDamageToMonster = monster.getStats().isBoss() ? 500000.0D : monster.getHp() - 1L;
defined = true;
break;
case 3211006:
if (monster.getStatusSourceID(MonsterStatus.FREEZE) == 3211003) {
defined = true;
maximumDamageToMonster = 999999.0D;
}
break;
}
}
double elementalMaxDamagePerMonster = maximumDamageToMonster;
if ((player.getJob() == 311) || (player.getJob() == 312) || (player.getJob() == 321) || (player.getJob() == 322)) {
Skill mortal = SkillFactory.getSkill((player.getJob() == 311) || (player.getJob() == 312) ? 3110001 : 3210001);
if (player.getTotalSkillLevel(mortal) > 0) {
MapleStatEffect mort = mortal.getEffect(player.getTotalSkillLevel(mortal));
if ((mort != null) && (monster.getHPPercent() < mort.getX())) {
elementalMaxDamagePerMonster = 999999.0D;
defined = true;
// if (mort.getZ() > 0)
// player.addHP(player.getStat().getMaxHp() * mort.getZ() / 100);
}
}
} else if ((player.getJob() == 221) || (player.getJob() == 222)) {
Skill mortal = SkillFactory.getSkill(2210000);
if (player.getTotalSkillLevel(mortal) > 0) {
MapleStatEffect mort = mortal.getEffect(player.getTotalSkillLevel(mortal));
if ((mort != null) && (monster.getHPPercent() < mort.getX())) {
elementalMaxDamagePerMonster = 999999.0D;
defined = true;
}
}
}
if ((!defined) || ((theSkill != null) && ((theSkill.getId() == 33101001) || (theSkill.getId() == 3221001)))) {
if (player.getBuffedValue(MapleBuffStat.WK_CHARGE) != null) {
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:
}
}
if (player.getBuffedValue(MapleBuffStat.LIGHTNING_CHARGE) != null) {
elements.add(Element.LIGHTING);
}
if (player.getBuffedValue(MapleBuffStat.ELEMENT_RESET) != null) {
elements.clear();
}
double elementalEffect;
if (elements.size() > 0) {
switch (attack.skill) {
case 3111003:
case 3211003:
elementalEffect = attackEffect.getX() / 100.0D;
break;
default:
elementalEffect = 0.5D / elements.size();
}
for (Element element : elements) {
switch (monster.getEffectiveness(element)) {
case IMMUNE:
elementalMaxDamagePerMonster = 1.0D;
break;
case WEAK:
elementalMaxDamagePerMonster *= (1.0D + elementalEffect + player.getStat().getElementBoost(element));
break;
case STRONG:
elementalMaxDamagePerMonster *= (1.0D - elementalEffect - player.getStat().getElementBoost(element));
}
}
}
elementalMaxDamagePerMonster -= elementalMaxDamagePerMonster * (Math.max(PDRate - Math.max(player.getStat().ignoreTargetDEF, 0) - Math.max(attackEffect == null ? 0 : attackEffect.getIgnoreMob(), 0), 0) / 100.0D);
elementalMaxDamagePerMonster += elementalMaxDamagePerMonster / 100.0D * CritPercent;
MonsterStatusEffect imprint = monster.getBuff(MonsterStatus.IMPRINT);
if (imprint != null) {
elementalMaxDamagePerMonster += elementalMaxDamagePerMonster * imprint.getX().intValue() / 100.0D;
}
elementalMaxDamagePerMonster += elementalMaxDamagePerMonster * player.getDamageIncrease(monster.getObjectId()) / 100.0D;
elementalMaxDamagePerMonster *= ((monster.getStats().isBoss()) && (attackEffect != null) ? player.getStat().bossdam_r + attackEffect.getBossDamage() : player.getStat().dam_r) / 100.0D;
}
if (elementalMaxDamagePerMonster > 999999.0D) {
if (!defined) {
elementalMaxDamagePerMonster = 999999.0D;
}
} else if (elementalMaxDamagePerMonster <= 0.0D) {
elementalMaxDamagePerMonster = 1.0D;
}
return elementalMaxDamagePerMonster;
}
public static final AttackInfo DivideAttack(final AttackInfo attack, final int rate) {
if (rate <= 1) {
return attack; //lol
}
for (AttackPair p : attack.allDamage) {
if (p.attack != null) {
for (Pair<Integer, Boolean> eachd : p.attack) {
eachd.left /= rate; //too ex.
}
}
}
return attack;
}
public static final AttackInfo Modify_AttackCrit(AttackInfo attack, MapleCharacter chr, int type, MapleStatEffect effect) {
int CriticalRate;
boolean shadow;
List damages;
List damage;
if ((attack.skill != 4211006) && (attack.skill != 3211003) && (attack.skill != 4111004)) {
CriticalRate = chr.getStat().passive_sharpeye_rate() + (effect == null ? 0 : effect.getCr());
shadow = (chr.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) && ((type == 1) || (type == 2));
damages = new ArrayList();
damage = new ArrayList();
for (AttackPair p : attack.allDamage) {
if (p.attack != null) {
int hit = 0;
int mid_att = shadow ? p.attack.size() / 2 : p.attack.size();
int toCrit = (attack.skill == 4221001) || (attack.skill == 3221007) || (attack.skill == 23121003) || (attack.skill == 4341005) || (attack.skill == 4331006) || (attack.skill == 21120005) ? mid_att : 0;
if (toCrit == 0) {
for (Pair eachd : p.attack) {
if ((!((Boolean) eachd.right).booleanValue()) && (hit < mid_att)) {
if ((((Integer) eachd.left).intValue() > 999999) || (Randomizer.nextInt(100) < CriticalRate)) {
toCrit++;
}
damage.add(eachd.left);
}
hit++;
}
if (toCrit == 0) {
damage.clear();
} else {
Collections.sort(damage);
for (int i = damage.size(); i > damage.size() - toCrit; i--) {
damages.add(damage.get(i - 1));
}
damage.clear();
}
} else {
hit = 0;
for (Pair eachd : p.attack) {
if (!((Boolean) eachd.right).booleanValue()) {
if (attack.skill == 4221001) {
eachd.right = Boolean.valueOf(hit == 3);
} else if ((attack.skill == 3221007) || (attack.skill == 23121003) || (attack.skill == 21120005) || (attack.skill == 4341005) || (attack.skill == 4331006) || (((Integer) eachd.left).intValue() > 999999)) {
eachd.right = Boolean.valueOf(true);
} else if (hit >= mid_att) {
eachd.right = ((Pair) p.attack.get(hit - mid_att)).right;
} else {
eachd.right = Boolean.valueOf(damages.contains(eachd.left));
}
}
hit++;
}
damages.clear();
}
}
}
}
return attack;
}
public static final AttackInfo parseDmgMa(LittleEndianAccessor lea, MapleCharacter chr) {
try {
AttackInfo ret = new AttackInfo();
lea.skip(1);
ret.tbyte = lea.readByte();
ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));
ret.hits = ((byte) (ret.tbyte & 0xF));
ret.skill = lea.readInt();
if (ret.skill >= 91000000) {
return null;
}
lea.skip(11);
if (GameConstants.isMagicChargeSkill(ret.skill)) {
ret.charge = lea.readInt();
} else {
ret.charge = -1;
}
lea.skip(1);
ret.display = lea.readByte(); // Always zero?
ret.animation = lea.readByte();
lea.skip(4);
ret.speed = lea.readByte();
ret.lastAttackTickCount = lea.readInt();
lea.skip(4);
ret.allDamage = new ArrayList();
for (int i = 0; i < ret.targets; i++) {
int oid = lea.readInt();
lea.skip(20);
List allDamageNumbers = new ArrayList();
for (int j = 0; j < ret.hits; j++) {
int damage = lea.readInt();
allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
}
lea.skip(8);
ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
}
if (lea.available() >= 4L) {
ret.position = lea.readPos();
}
return ret;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static final AttackInfo parseDmgM(LittleEndianAccessor lea, MapleCharacter chr) {
AttackInfo ret = new AttackInfo();
lea.skip(1);
ret.tbyte = lea.readByte();
ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));
ret.hits = ((byte) (ret.tbyte & 0xF));
ret.skill = lea.readInt();
if (ret.skill >= 91000000) {
return null;
}
lea.skip(11);
switch (ret.skill) {
case 4341002:
case 4341003:
case 5201002:
case 5300007:
case 5301001:
case 14111006:
case 24121000:
case 24121005:
case 36101001:
case 27101202:
case 2221052:
case 27111100:
case 65121052:
case 27120211:
case 27121201:
case 31001000:
case 20041226:
case 31101000:
case 4221052:
case 31111005:
case 36121000:
case 61111100:
case 61111111:
case 61111113:
case 65121003:
case 5101012:
case 15101010:
case 32121003: //����Ŭ��
case 31201001:
case 31211001:
case 2221012:
case 11121052:
case 5121013:
case 1311011:
ret.charge = lea.readInt();
break;
default:
ret.charge = 0;
}
lea.skip(1);
ret.display = lea.readByte(); // Always zero?
ret.animation = lea.readByte(); //unk
lea.skip(5);
if ((ret.skill == 5300007) || (ret.skill == 5101012) || (ret.skill == 5081001) || (ret.skill == 15101010)) {
lea.readInt();
}
ret.speed = lea.readByte();
ret.lastAttackTickCount = lea.readInt();
if (ret.skill == 32121003) {
lea.skip(4);
} else if (ret.skill == 4341052) {
lea.skip(3);
} else {
lea.skip(8);
}
ret.allDamage = new ArrayList();
if (ret.skill == 4211006) {
return parseMesoExplosion(lea, ret, chr);
}
for (int i = 0; i < ret.targets; i++) {
int oid = lea.readInt();
lea.skip(20);
List allDamageNumbers = new ArrayList();
for (int j = 0; j < ret.hits; j++) {
int damage = lea.readInt();
// if (chr.getJob() == 3122) {
//
// if (chr.getReborns() > 1) {
// damage += (chr.getReborns() + 1) * chr.getStat().getMaxHp();
// } else {
// damage += 1 * chr.getStat().getMaxHp();
// }
// if (damage > 50000000) {
// damage = 50000000;
// }
// if (chr.getAccountID() == 1 && chr.getJob() == 3122) {
// chr.dropMessage(6, "" + damage);
// }
// }
allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
}
lea.skip(8);
ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
}
ret.position = lea.readPos();
return ret;
}
// public static final AttackInfo parseAsura(LittleEndianAccessor lea, MapleCharacter chr) {
// AttackInfo ret = new AttackInfo();
// lea.skip(1);
// ret.tbyte = lea.readByte();
//
// ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));
// ret.hits = ((byte) (ret.tbyte & 0xF));
// ret.skill = lea.readInt();
// if (ret.skill >= 91000000) {
// return null;
// }
// lea.skip(11);
// switch (ret.skill) {
// case 4341002:
// case 4341003:
// case 5201002:
// case 5300007:
// case 5301001:
// case 14111006:
// case 24121000:
// case 24121005:
// case 36101001:
// case 27101202:
// case 2221052:
// case 27111100:
// case 65121052:
// case 27120211:
// //case 4341052:
// case 27121201:
// case 31001000:
// case 20041226:
// case 31101000:
// case 4221052:
// case 31111005:
// case 36121000:
// case 61111100:
// case 61111111:
// case 61111113:
// case 65121003:
//
// case 5101012:
// case 15101010:
//
// case 32121003: //����Ŭ��
//
// case 31201001:
// case 31211001:
//
// case 2221012:
// case 11121052:
// case 5121013:
// case 1311011:
//
//
// ret.charge = lea.readInt();
// break;
// default:
// ret.charge = 0;
// }
//
// lea.skip(1);
// ret.display = lea.readByte(); // Always zero?
// ret.animation = lea.readByte(); //unk
// chr.dropMessage(5, "X: "+lea);
// lea.skip(5);
// if ((ret.skill == 5300007) || (ret.skill == 5101012) || (ret.skill == 5081001) || (ret.skill == 15101010)) {
// lea.readInt();
// }
// ret.speed = lea.readByte();
// chr.dropMessage(5, "Y: "+lea);
// // lea.skip(3);
// ret.lastAttackTickCount = lea.readInt();
// if (ret.skill == 32121003) {
// lea.skip(4);
// } else if (ret.skill == 4341052) {
// lea.skip(3);
// } else {
// lea.skip(8);
// }
//
// ret.allDamage = new ArrayList();
//
// if (ret.skill == 4211006) {
// return parseMesoExplosion(lea, ret, chr);
// }
// for (int i = 0; i < ret.targets; i++) {
// int oid = lea.readInt();
//
// lea.skip(20);
//
//
//
// List allDamageNumbers = new ArrayList();
//
// for (int j = 0; j < ret.hits; j++) {
//
// int damage = lea.readInt();
//// if (chr.getJob() == 3122) {
////
//// if (chr.getReborns() > 1) {
//// damage += (chr.getReborns() + 1) * chr.getStat().getMaxHp();
//// } else {
//// damage += 1 * chr.getStat().getMaxHp();
//// }
//// if (damage > 50000000) {
//// damage = 50000000;
//// }
//// if (chr.getAccountID() == 1 && chr.getJob() == 3122) {
//// chr.dropMessage(6, "" + damage);
//// }
//// }
// allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
// }
// lea.skip(8);
// ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
// }
// ret.position = lea.readPos();
// return ret;
// }
public static final AttackInfo parseDmgR(LittleEndianAccessor lea, MapleCharacter chr) {
AttackInfo ret = new AttackInfo();
try {
lea.skip(1);
ret.tbyte = lea.readByte();
ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));
ret.hits = ((byte) (ret.tbyte & 0xF));
ret.skill = lea.readInt();
if (ret.skill >= 91000000) {
return null;
}
lea.skip(11);
switch (ret.skill) {
case 3121004:
case 5321052:
case 3221001:
case 5221004:
case 5311002:
case 5711002:
case 5721001:
case 13111002:
case 23121000:
case 24121000:
case 33121009:
case 35001001:
case 35101009:
case 60011216:
case 13121001:
case 13111020:
case 3121013:
case 3101008:
case 3111009:
case 3120019:
lea.skip(4);
}
ret.charge = -1;
ret.display = lea.readByte(); // Always zero?
ret.animation = lea.readByte();
lea.skip(1);
lea.skip(5);
if (ret.skill == 23111001) {
lea.skip(12);
}
ret.speed = lea.readByte();
ret.lastAttackTickCount = lea.readInt();
lea.skip(4);
ret.slot = ((byte) lea.readShort());
ret.csstar = ((byte) lea.readShort());
ret.AOE = lea.readByte();
ret.allDamage = new ArrayList();
for (int i = 0; i < ret.targets; i++) {
int oid = lea.readInt();
lea.skip(20);
List allDamageNumbers = new ArrayList();
for (int j = 0; j < ret.hits; j++) {
int damage = lea.readInt();
allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
}
lea.skip(8);
ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
}
ret.position = lea.readPos();
} catch(NullPointerException dd) {
}
return ret;
}
public static final AttackInfo parseMesoExplosion(LittleEndianAccessor lea, AttackInfo ret, MapleCharacter chr) {
if (ret.hits == 0) {
lea.skip(4);
byte bullets = lea.readByte();
for (int j = 0; j < bullets; j++) {
ret.allDamage.add(new AttackPair(Integer.valueOf(lea.readInt()).intValue(), null));
lea.skip(1);
}
lea.skip(2);
return ret;
}
for (int i = 0; i < ret.targets; i++) {
int oid = lea.readInt();
lea.skip(12);
byte bullets = lea.readByte();
List allDamageNumbers = new ArrayList();
for (int j = 0; j < bullets; j++) {
allDamageNumbers.add(new Pair(Integer.valueOf(lea.readInt()), Boolean.valueOf(false)));
}
ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
lea.skip(4);
}
lea.skip(4);
byte bullets = lea.readByte();
for (int j = 0; j < bullets; j++) {
ret.allDamage.add(new AttackPair(Integer.valueOf(lea.readInt()).intValue(), null));
lea.skip(2);
}
return ret;
}
}