/* OrpheusMS: MapleStory Private Server based on OdinMS Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net> Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan Christian Meyer <vimes@odinms.de> This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package server; import java.awt.Point; import java.awt.Rectangle; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledFuture; import client.IItem; import client.ISkill; import client.MapleBuffStat; import client.MapleCharacter; import client.MapleDisease; import client.MapleInventory; import client.MapleInventoryType; import client.MapleJob; import client.MapleMount; import client.MapleStat; import client.MapleStatDelta; import client.SkillFactory; import client.status.MonsterStatus; import client.status.MonsterStatusEffect; import constants.ItemConstants; import constants.skills.Aran; import constants.skills.Assassin; import constants.skills.Bandit; import constants.skills.Beginner; import constants.skills.Bishop; import constants.skills.BlazeWizard; import constants.skills.Bowmaster; import constants.skills.Brawler; import constants.skills.Buccaneer; import constants.skills.ChiefBandit; import constants.skills.Cleric; import constants.skills.Corsair; import constants.skills.Crossbowman; import constants.skills.Crusader; import constants.skills.DarkKnight; import constants.skills.DawnWarrior; import constants.skills.DragonKnight; import constants.skills.FPArchMage; import constants.skills.FPMage; import constants.skills.FPWizard; import provider.MapleData; import provider.MapleDataTool; import server.life.MapleMonster; import server.maps.MapleDoor; import server.maps.MapleMap; import server.maps.MapleMapObject; import server.maps.MapleMapObjectType; import server.maps.MapleMist; import server.maps.MapleSummon; import server.maps.SummonMovementType; import net.server.PlayerCoolDownValueHolder; import tools.ArrayMap; import tools.MaplePacketCreator; import constants.skills.Fighter; import constants.skills.GM; import constants.skills.Gunslinger; import constants.skills.Hermit; import constants.skills.Hero; import constants.skills.Hunter; import constants.skills.ILArchMage; import constants.skills.ILMage; import constants.skills.ILWizard; import constants.skills.Legend; import constants.skills.Magician; import constants.skills.Marauder; import constants.skills.Marksman; import constants.skills.NightLord; import constants.skills.NightWalker; import constants.skills.Noblesse; import constants.skills.Outlaw; import constants.skills.Page; import constants.skills.Paladin; import constants.skills.Pirate; import constants.skills.Priest; import constants.skills.Ranger; import constants.skills.Rogue; import constants.skills.Shadower; import constants.skills.Sniper; import constants.skills.Spearman; import constants.skills.SuperGM; import constants.skills.ThunderBreaker; import constants.skills.WhiteKnight; import constants.skills.WindArcher; import net.MaplePacket; import server.maps.FieldLimit; /** * @author Matze * @author Frz */ public class MapleStatEffect { private short watk, matk, wdef, mdef, acc, avoid, speed, jump; private short hp, mp; private double hpR, mpR; private short mpCon, hpCon; private int duration; private boolean overTime, repeatEffect; private int sourceid; private int moveTo; private boolean skill; private List<MapleBuffStatDelta> statups; private Map<MonsterStatus, Integer> monsterStatus; private int x, y, mobCount, moneyCon, cooldown, morphId = 0, ghost, fatigue, berserk, booster; private double prop; private int itemCon, itemConNo; private int damage, attackCount, fixdamage; private Point lt, rb; private byte bulletCount, bulletConsume; public static MapleStatEffect loadSkillEffectFromData(MapleData source, int skillid, boolean overtime) { return loadFromData(source, skillid, true, overtime); } public static MapleStatEffect loadItemEffectFromData(MapleData source, int itemid) { return loadFromData(source, itemid, false, false); } private static void addBuffStatDeltaToListIfNotZero(List<MapleBuffStatDelta> list, MapleBuffStat buffstat, int val) { if (val != 0) { list.add(new MapleBuffStatDelta(buffstat, val)); } } private static MapleStatEffect loadFromData(MapleData source, int sourceid, boolean skill, boolean overTime) { MapleStatEffect ret = new MapleStatEffect(); ret.duration = MapleDataTool.getIntConvert("time", source, -1); ret.hp = (short) MapleDataTool.getInt("hp", source, 0); ret.hpR = MapleDataTool.getInt("hpR", source, 0) / 100.0; ret.mp = (short) MapleDataTool.getInt("mp", source, 0); ret.mpR = MapleDataTool.getInt("mpR", source, 0) / 100.0; ret.mpCon = (short) MapleDataTool.getInt("mpCon", source, 0); ret.hpCon = (short) MapleDataTool.getInt("hpCon", source, 0); int iprop = MapleDataTool.getInt("prop", source, 100); ret.prop = iprop / 100.0; ret.mobCount = MapleDataTool.getInt("mobCount", source, 1); ret.cooldown = MapleDataTool.getInt("cooltime", source, 0); ret.morphId = MapleDataTool.getInt("morph", source, 0); ret.ghost = MapleDataTool.getInt("ghost", source, 0); ret.fatigue = MapleDataTool.getInt("incFatigue", source, 0); ret.repeatEffect = MapleDataTool.getInt("repeatEffect", source, 0) > 0; ret.sourceid = sourceid; ret.skill = skill; if (!ret.skill && ret.duration > -1) { ret.overTime = true; } else { ret.duration *= 1000; // items have their times stored in ms, of // course ret.overTime = overTime; } ArrayList<MapleBuffStatDelta> statups = new ArrayList<MapleBuffStatDelta>(); ret.watk = (short) MapleDataTool.getInt("pad", source, 0); ret.wdef = (short) MapleDataTool.getInt("pdd", source, 0); ret.matk = (short) MapleDataTool.getInt("mad", source, 0); ret.mdef = (short) MapleDataTool.getInt("mdd", source, 0); ret.acc = (short) MapleDataTool.getIntConvert("acc", source, 0); ret.avoid = (short) MapleDataTool.getInt("eva", source, 0); ret.speed = (short) MapleDataTool.getInt("speed", source, 0); ret.jump = (short) MapleDataTool.getInt("jump", source, 0); ret.berserk = MapleDataTool.getInt("berserk", source, 0); ret.booster = MapleDataTool.getInt("booster", source, 0); if (ret.overTime && ret.getSummonMovementType() == null) { addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.WATK, ret.watk); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.WDEF, ret.wdef); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.MATK, ret.matk); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.MDEF, ret.mdef); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.ACC, ret.acc); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.AVOID, ret.avoid); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.SPEED, ret.speed); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.JUMP, ret.jump); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.PYRAMID_PQ, ret.berserk); addBuffStatDeltaToListIfNotZero(statups, MapleBuffStat.BOOSTER, ret.booster); } MapleData ltd = source.getChildByPath("lt"); if (ltd != null) { ret.lt = (Point) ltd.getData(); ret.rb = (Point) source.getChildByPath("rb").getData(); } int x = MapleDataTool.getInt("x", source, 0); ret.x = x; ret.y = MapleDataTool.getInt("y", source, 0); ret.damage = MapleDataTool.getIntConvert("damage", source, 100); ret.fixdamage = MapleDataTool.getIntConvert("fixdamage", source, -1); ret.attackCount = MapleDataTool.getIntConvert("attackCount", source, 1); ret.bulletCount = (byte) MapleDataTool.getIntConvert("bulletCount", source, 1); ret.bulletConsume = (byte) MapleDataTool.getIntConvert("bulletConsume", source, 0); ret.moneyCon = MapleDataTool.getIntConvert("moneyCon", source, 0); ret.itemCon = MapleDataTool.getInt("itemCon", source, 0); ret.itemConNo = MapleDataTool.getInt("itemConNo", source, 0); ret.moveTo = MapleDataTool.getInt("moveTo", source, -1); Map<MonsterStatus, Integer> monsterStatus = new ArrayMap<MonsterStatus, Integer>(); if (skill) { switch (sourceid) { // BEGINNER case Beginner.RECOVERY: case Noblesse.RECOVERY: case Legend.RECOVERY: statups.add(new MapleBuffStatDelta(MapleBuffStat.RECOVERY, x)); break; case Beginner.ECHO_OF_HERO: case Noblesse.ECHO_OF_HERO: case Legend.ECHO_OF_HERO: statups.add(new MapleBuffStatDelta(MapleBuffStat.ECHO_OF_HERO, ret.x)); break; case Beginner.MONSTER_RIDER: case Noblesse.MONSTER_RIDER: case Legend.MONSTER_RIDER: case Corsair.BATTLE_SHIP: case Beginner.SPACESHIP: case Noblesse.SPACESHIP: case Beginner.YETI_MOUNT1: case Beginner.YETI_MOUNT2: case Noblesse.YETI_MOUNT1: case Noblesse.YETI_MOUNT2: case Legend.YETI_MOUNT1: case Legend.YETI_MOUNT2: case Beginner.WITCH_BROOMSTICK: case Noblesse.WITCH_BROOMSTICK: case Legend.WITCH_BROOMSTICK: case Beginner.BALROG_MOUNT: case Noblesse.BALROG_MOUNT: case Legend.BALROG_MOUNT: statups.add(new MapleBuffStatDelta(MapleBuffStat.MONSTER_RIDING, sourceid)); break; case Beginner.BERSERK_FURY: case Noblesse.BERSERK_FURY: statups.add(new MapleBuffStatDelta(MapleBuffStat.BERSERK_FURY, 1)); break; case Beginner.INVINCIBLE_BARRIER: case Noblesse.INVINCIBLE_BARRIER: case Legend.INVICIBLE_BARRIER: statups.add(new MapleBuffStatDelta(MapleBuffStat.DIVINE_BODY, 1)); break; case Fighter.POWER_GUARD: case Page.POWER_GUARD: statups.add(new MapleBuffStatDelta(MapleBuffStat.POWERGUARD, x)); break; case Spearman.HYPER_BODY: case GM.HYPER_BODY: case SuperGM.HYPER_BODY: statups.add(new MapleBuffStatDelta(MapleBuffStat.HYPERBODYHP, x)); statups.add(new MapleBuffStatDelta(MapleBuffStat.HYPERBODYMP, ret.y)); break; case Crusader.COMBO: case DawnWarrior.COMBO: statups.add(new MapleBuffStatDelta(MapleBuffStat.COMBO, 1)); break; case WhiteKnight.BW_FIRE_CHARGE: case WhiteKnight.BW_ICE_CHARGE: case WhiteKnight.BW_LIT_CHARGE: case WhiteKnight.SWORD_FIRE_CHARGE: case WhiteKnight.SWORD_ICE_CHARGE: case WhiteKnight.SWORD_LIT_CHARGE: case Paladin.BW_HOLY_CHARGE: case Paladin.SWORD_HOLY_CHARGE: case DawnWarrior.SOUL_CHARGE: case ThunderBreaker.LIGHTNING_CHARGE: statups.add(new MapleBuffStatDelta(MapleBuffStat.WK_CHARGE, x)); break; case DragonKnight.DRAGON_BLOOD: statups.add(new MapleBuffStatDelta(MapleBuffStat.DRAGONBLOOD, ret.x)); break; case DragonKnight.DRAGON_ROAR: ret.hpR = -x / 100.0; break; case Hero.STANCE: case Paladin.STANCE: case DarkKnight.STANCE: case Aran.FREEZE_STANDING: statups.add(new MapleBuffStatDelta(MapleBuffStat.STANCE, iprop)); break; case DawnWarrior.FINAL_ATTACK: case WindArcher.FINAL_ATTACK: statups.add(new MapleBuffStatDelta(MapleBuffStat.FINALATTACK, x)); break; // MAGICIAN case Magician.MAGIC_GUARD: case BlazeWizard.MAGIC_GUARD: statups.add(new MapleBuffStatDelta(MapleBuffStat.MAGIC_GUARD, x)); break; case Cleric.INVINCIBLE: statups.add(new MapleBuffStatDelta(MapleBuffStat.INVINCIBLE, x)); break; case Priest.HOLY_SYMBOL: case SuperGM.HOLY_SYMBOL: statups.add(new MapleBuffStatDelta(MapleBuffStat.HOLY_SYMBOL, x)); break; case FPArchMage.INFINITY: case ILArchMage.INFINITY: case Bishop.INFINITY: statups.add(new MapleBuffStatDelta(MapleBuffStat.INFINITY, x)); break; case FPArchMage.MANA_REFLECTION: case ILArchMage.MANA_REFLECTION: case Bishop.MANA_REFLECTION: statups.add(new MapleBuffStatDelta(MapleBuffStat.MANA_REFLECTION, 1)); break; case Bishop.HOLY_SHIELD: statups.add(new MapleBuffStatDelta(MapleBuffStat.HOLY_SHIELD, x)); break; // BOWMAN case Priest.MYSTIC_DOOR: case Hunter.SOUL_ARROW: case Crossbowman.SOUL_ARROW: case WindArcher.SOUL_ARROW: statups.add(new MapleBuffStatDelta(MapleBuffStat.SOULARROW, x)); break; case Ranger.PUPPET: case Sniper.PUPPET: case WindArcher.PUPPET: case Outlaw.OCTOPUS: case Corsair.WRATH_OF_THE_OCTOPI: statups.add(new MapleBuffStatDelta(MapleBuffStat.PUPPET, 1)); break; case Bowmaster.CONCENTRATE: statups.add(new MapleBuffStatDelta(MapleBuffStat.CONCENTRATE, x)); break; case Bowmaster.HAMSTRING: statups.add(new MapleBuffStatDelta(MapleBuffStat.HAMSTRING, x)); monsterStatus.put(MonsterStatus.SPEED, Integer.valueOf(x)); break; case Marksman.BLIND: statups.add(new MapleBuffStatDelta(MapleBuffStat.BLIND, x)); monsterStatus.put(MonsterStatus.ACC, Integer.valueOf(x)); break; case Bowmaster.SHARP_EYES: case Marksman.SHARP_EYES: final int delta = ret.x << 8 | ret.y; statups.add(new MapleBuffStatDelta(MapleBuffStat.SHARP_EYES, delta)); break; // THIEF case Rogue.DARK_SIGHT: case WindArcher.WIND_WALK: case NightWalker.DARK_SIGHT: statups.add(new MapleBuffStatDelta(MapleBuffStat.DARKSIGHT, x)); break; case Hermit.MESO_UP: statups.add(new MapleBuffStatDelta(MapleBuffStat.MESOUP, x)); break; case Hermit.SHADOW_PARTNER: case NightWalker.SHADOW_PARTNER: statups.add(new MapleBuffStatDelta(MapleBuffStat.SHADOWPARTNER, x)); break; case ChiefBandit.MESO_GUARD: statups.add(new MapleBuffStatDelta(MapleBuffStat.MESOGUARD, x)); break; case ChiefBandit.PICKPOCKET: statups.add(new MapleBuffStatDelta(MapleBuffStat.PICKPOCKET, x)); break; case NightLord.SHADOW_STARS: statups.add(new MapleBuffStatDelta(MapleBuffStat.SHADOW_CLAW, 0)); break; // PIRATE case Pirate.DASH: case ThunderBreaker.DASH: case Beginner.SPACE_DASH: case Noblesse.SPACE_DASH: statups.add(new MapleBuffStatDelta(MapleBuffStat.DASH2, ret.x)); statups.add(new MapleBuffStatDelta(MapleBuffStat.DASH, ret.y)); break; case Corsair.SPEED_INFUSION: case Buccaneer.SPEED_INFUSION: case ThunderBreaker.SPEED_INFUSION: statups.add(new MapleBuffStatDelta(MapleBuffStat.SPEED_INFUSION, x)); break; case Outlaw.HOMING_BEACON: case Corsair.BULLSEYE: statups.add(new MapleBuffStatDelta(MapleBuffStat.HOMING_BEACON, x)); break; case ThunderBreaker.SPARK: statups.add(new MapleBuffStatDelta(MapleBuffStat.SPARK, x)); break; // MULTIPLE case Aran.POLEARM_BOOSTER: case Fighter.AXE_BOOSTER: case Fighter.SWORD_BOOSTER: case Page.BW_BOOSTER: case Page.SWORD_BOOSTER: case Spearman.POLEARM_BOOSTER: case Spearman.SPEAR_BOOSTER: case Hunter.BOW_BOOSTER: case Crossbowman.CROSSBOW_BOOSTER: case Assassin.CLAW_BOOSTER: case Bandit.DAGGER_BOOSTER: case FPMage.SPELL_BOOSTER: case ILMage.SPELL_BOOSTER: case Brawler.KNUCKLER_BOOSTER: case Gunslinger.GUN_BOOSTER: case DawnWarrior.SWORD_BOOSTER: case BlazeWizard.SPELL_BOOSTER: case WindArcher.BOW_BOOSTER: case NightWalker.CLAW_BOOSTER: case ThunderBreaker.KNUCKLER_BOOSTER: statups.add(new MapleBuffStatDelta(MapleBuffStat.BOOSTER, x)); break; case Hero.MAPLE_WARRIOR: case Paladin.MAPLE_WARRIOR: case DarkKnight.MAPLE_WARRIOR: case FPArchMage.MAPLE_WARRIOR: case ILArchMage.MAPLE_WARRIOR: case Bishop.MAPLE_WARRIOR: case Bowmaster.MAPLE_WARRIOR: case Marksman.MAPLE_WARRIOR: case NightLord.MAPLE_WARRIOR: case Shadower.MAPLE_WARRIOR: case Corsair.MAPLE_WARRIOR: case Buccaneer.MAPLE_WARRIOR: case Aran.MAPLE_WARRIOR: statups.add(new MapleBuffStatDelta(MapleBuffStat.MAPLE_WARRIOR, ret.x)); break; // SUMMON case Ranger.SILVER_HAWK: case Sniper.GOLDEN_EAGLE: statups.add(new MapleBuffStatDelta(MapleBuffStat.SUMMON, 1)); monsterStatus.put(MonsterStatus.STUN, Integer.valueOf(1)); break; case FPArchMage.ELQUINES: case Marksman.FROST_PREY: statups.add(new MapleBuffStatDelta(MapleBuffStat.SUMMON, 1)); monsterStatus.put(MonsterStatus.FREEZE, Integer.valueOf(1)); break; case Priest.SUMMON_DRAGON: case Bowmaster.PHOENIX: case ILArchMage.IFRIT: case Bishop.BAHAMUT: case DarkKnight.BEHOLDER: case Outlaw.GAVIOTA: case DawnWarrior.SOUL: case BlazeWizard.FLAME: case WindArcher.STORM: case NightWalker.DARKNESS: case ThunderBreaker.LIGHTNING: case BlazeWizard.IFRIT: statups.add(new MapleBuffStatDelta(MapleBuffStat.SUMMON, 1)); break; // ----------------------------- MONSTER STATUS // ---------------------------------- // case Rogue.DISORDER: monsterStatus.put(MonsterStatus.WATK, Integer.valueOf(ret.x)); monsterStatus.put(MonsterStatus.WDEF, Integer.valueOf(ret.y)); break; case Corsair.HYPNOTIZE: monsterStatus.put(MonsterStatus.INERTMOB, Integer.valueOf(1)); break; case NightLord.NINJA_AMBUSH: case Shadower.NINJA_AMBUSH: monsterStatus.put(MonsterStatus.NINJA_AMBUSH, Integer.valueOf(ret.damage)); break; case Page.THREATEN: monsterStatus.put(MonsterStatus.WATK, Integer.valueOf(ret.x)); monsterStatus.put(MonsterStatus.WDEF, Integer.valueOf(ret.y)); break; case Crusader.AXE_COMA: case Crusader.SWORD_COMA: case Crusader.SHOUT: case WhiteKnight.CHARGE_BLOW: case Hunter.ARROW_BOMB: case ChiefBandit.ASSAULTER: case Shadower.BOOMERANG_STEP: case Brawler.BACK_SPIN_BLOW: case Brawler.DOUBLE_UPPERCUT: case Buccaneer.DEMOLITION: case Buccaneer.SNATCH: case Buccaneer.BARRAGE: case Gunslinger.BLANK_SHOT: case DawnWarrior.COMA: case Aran.ROLLING_SPIN: monsterStatus.put(MonsterStatus.STUN, Integer.valueOf(1)); break; case NightLord.TAUNT: case Shadower.TAUNT: monsterStatus.put(MonsterStatus.SHOWDOWN, Integer.valueOf(ret.x)); monsterStatus.put(MonsterStatus.MDEF, Integer.valueOf(ret.x)); monsterStatus.put(MonsterStatus.WDEF, Integer.valueOf(ret.x)); break; case ILWizard.COLD_BEAM: case ILMage.ICE_STRIKE: case ILArchMage.BLIZZARD: case ILMage.ELEMENT_COMPOSITION: case Sniper.BLIZZARD: case Outlaw.ICE_SPLITTER: case FPArchMage.PARALYZE: case Aran.COMBO_TEMPEST: monsterStatus.put(MonsterStatus.FREEZE, Integer.valueOf(1)); ret.duration *= 2; // freezing skills are a little strange break; case FPWizard.SLOW: case ILWizard.SLOW: case BlazeWizard.SLOW: monsterStatus.put(MonsterStatus.SPEED, Integer.valueOf(ret.x)); break; case FPWizard.POISON_BREATH: case FPMage.ELEMENT_COMPOSITION: monsterStatus.put(MonsterStatus.POISON, Integer.valueOf(1)); break; case Priest.DOOM: monsterStatus.put(MonsterStatus.DOOM, Integer.valueOf(1)); break; case ILMage.SEAL: case FPMage.SEAL: monsterStatus.put(MonsterStatus.SEAL, Integer.valueOf(1)); break; case Hermit.SHADOW_WEB: // shadow web case NightWalker.SHADOW_WEB: monsterStatus.put(MonsterStatus.SHADOW_WEB, Integer.valueOf(1)); break; case FPArchMage.FIRE_DEMON: case ILArchMage.ICE_DEMON: monsterStatus.put(MonsterStatus.POISON, Integer.valueOf(1)); monsterStatus.put(MonsterStatus.FREEZE, Integer.valueOf(1)); break; // ARAN case Aran.COMBO_ABILITY: statups.add(new MapleBuffStatDelta(MapleBuffStat.ARAN_COMBO, 100)); break; case Aran.COMBO_BARRIER: statups.add(new MapleBuffStatDelta(MapleBuffStat.COMBO_BARRIER, ret.x)); break; case Aran.COMBO_DRAIN: statups.add(new MapleBuffStatDelta(MapleBuffStat.COMBO_DRAIN, ret.x)); break; case Aran.SMART_KNOCKBACK: statups.add(new MapleBuffStatDelta(MapleBuffStat.SMART_KNOCKBACK, ret.x)); break; case Aran.BODY_PRESSURE: statups.add(new MapleBuffStatDelta(MapleBuffStat.BODY_PRESSURE, ret.x)); break; case Aran.SNOW_CHARGE: monsterStatus.put(MonsterStatus.SPEED, Integer.valueOf(ret.x)); statups.add(new MapleBuffStatDelta(MapleBuffStat.WK_CHARGE, ret.y)); break; default: break; } } if (ret.isMorph()) { statups.add(new MapleBuffStatDelta(MapleBuffStat.MORPH, ret.getMorph())); } if (ret.ghost > 0 && !skill) { statups.add(new MapleBuffStatDelta(MapleBuffStat.GHOST_MORPH, ret.ghost)); } ret.monsterStatus = monsterStatus; statups.trimToSize(); ret.statups = statups; return ret; } /** * @param applyto * @param obj * @param attack * damage done by the skill */ public void applyPassive(MapleCharacter applyto, MapleMapObject obj, int attack) { if (makeChanceResult()) { switch (sourceid) { // MP eater case FPWizard.MP_EATER: case ILWizard.MP_EATER: case Cleric.MP_EATER: if (obj == null || obj.getType() != MapleMapObjectType.MONSTER) { return; } MapleMonster mob = (MapleMonster) obj; // x is absorb // percentage if (!mob.isBoss()) { int absorbMp = Math.min((int) (mob.getMaxMp() * (getX() / 100.0)), mob.getMp()); if (absorbMp > 0) { mob.setMp(mob.getMp() - absorbMp); applyto.addMP(absorbMp); applyto.getClient().getSession().write(MaplePacketCreator.showOwnBuffEffect(sourceid, 1)); applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.showBuffeffect(applyto.getId(), sourceid, 1), false); } } break; } } } public boolean applyTo(MapleCharacter chr) { return applyTo(chr, chr, true, null); } public boolean applyTo(MapleCharacter chr, Point pos) { return applyTo(chr, chr, true, pos); } private boolean applyTo(MapleCharacter applyfrom, MapleCharacter applyto, boolean primary, Point pos) { if (skill && (sourceid == GM.HIDE || sourceid == SuperGM.HIDE)) { applyto.toggleHide(false); return true; } int hpchange = calcHPChange(applyfrom, primary); int mpchange = calcMPChange(applyfrom, primary); if (primary) { if (itemConNo != 0) { MapleInventoryManipulator.removeById(applyto.getClient(), MapleItemInformationProvider.getInstance().getInventoryType(itemCon), itemCon, itemConNo, false, true); } } List<MapleStatDelta> hpmpupdate = new ArrayList<MapleStatDelta>(2); if (!primary && isResurrection()) { hpchange = applyto.getMaxHp(); applyto.setStance(0); applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.removePlayerFromMap(applyto.getId()), false); applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.spawnPlayerMapobject(applyto), false); } if (isDispel() && makeChanceResult()) { applyto.dispelDebuffs(); } else if (isHeroWill()) { applyto.dispelDebuff(MapleDisease.SEDUCE); } if (isComboReset()) { applyto.setCombo((short) 0); } /* * if (applyfrom.getMp() < getMpCon()) { * AutobanFactory.MPCON.addPoint(applyfrom.getAutobanManager(), * "mpCon hack for skill:" + sourceid + "; Player MP: " + * applyto.getMp() + " MP Needed: " + getMpCon()); } */ if (hpchange != 0) { if (hpchange < 0 && (-hpchange) > applyto.getHp()) { return false; } int newHp = applyto.getHp() + hpchange; if (newHp < 1) { newHp = 1; } applyto.setHp(newHp); hpmpupdate.add(new MapleStatDelta(MapleStat.HP, applyto.getHp())); } int newMp = applyto.getMp() + mpchange; if (mpchange != 0) { if (mpchange < 0 && -mpchange > applyto.getMp()) return false; applyto.setMp(newMp); hpmpupdate.add(new MapleStatDelta(MapleStat.MP, applyto.getMp())); } applyto.getClient().getSession().write(MaplePacketCreator.updatePlayerStats(hpmpupdate, true)); if (moveTo != -1) { if (applyto.getMap().getReturnMapId() != applyto.getMapId()) { MapleMap target; if (moveTo == 999999999) { target = applyto.getMap().getReturnMap(); } else { target = applyto.getClient().getWorldServer().getChannel(applyto.getClient().getChannel()).getMapFactory().getMap(moveTo); int targetid = target.getId() / 10000000; if (targetid != 60 && applyto.getMapId() / 10000000 != 61 && targetid != applyto.getMapId() / 10000000 && targetid != 21 && targetid != 20) { return false; } } applyto.changeMap(target); } else return false; } if (isShadowClaw()) { int projectile = 0; MapleInventory use = applyto.getInventory(MapleInventoryType.USE); for (int i = 0; i < 97; i++) { // impose order... IItem item = use.getItem((byte) i); if (item != null) { if (ItemConstants.isThrowingStar(item.getItemId()) && item.getQuantity() >= 200) { projectile = item.getItemId(); break; } } } if (projectile == 0) return false; else MapleInventoryManipulator.removeById(applyto.getClient(), MapleInventoryType.USE, projectile, 200, false, true); } SummonMovementType summonMovementType = getSummonMovementType(); if (overTime || isCygnusFA() || summonMovementType != null) applyBuffEffect(applyfrom, applyto, primary); if (primary && (overTime || isHeal())) applyBuff(applyfrom); if (primary && isMonsterBuff()) applyMonsterBuff(applyfrom); if (this.getFatigue() != 0) applyto.getMount().setTiredness(applyto.getMount().getTiredness() + this.getFatigue()); if (summonMovementType != null && pos != null) { final MapleSummon tosummon = new MapleSummon(applyfrom, sourceid, pos, summonMovementType); applyfrom.getMap().spawnSummon(tosummon); applyfrom.addSummon(sourceid, tosummon); tosummon.addHP(x); if (isBeholder()) { tosummon.addHP(1); } } if (isMagicDoor() && !FieldLimit.DOOR.check(applyto.getMap().getFieldLimit())) { // Magic // Door Point doorPosition = new Point(applyto.getPosition()); MapleDoor door = new MapleDoor(applyto, doorPosition); applyto.getMap().spawnDoor(door); applyto.addDoor(door); door = new MapleDoor(door); applyto.addDoor(door); door.getTown().spawnDoor(door); if (applyto.getParty() != null) {// update town doors applyto.silentPartyUpdate(); } applyto.disableDoor(); } else if (isMist()) { Rectangle bounds = calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft()); MapleMist mist = new MapleMist(bounds, applyfrom, this); applyfrom.getMap().spawnMist(mist, getDuration(), sourceid != Shadower.SMOKE_SCREEN, false); } else if (isTimeLeap()) { // Time Leap for (PlayerCoolDownValueHolder i : applyto.getAllCooldowns()) { if (i.skillId != Buccaneer.TIME_LEAP) { applyto.removeCooldown(i.skillId); } } } return true; } private void applyBuff(MapleCharacter applyfrom) { if (isPartyBuff() && (applyfrom.getParty() != null || isGmBuff())) { Rectangle bounds = calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft()); List<MapleMapObject> affecteds = applyfrom.getMap().getMapObjectsInRect(bounds, Arrays.asList(MapleMapObjectType.PLAYER)); List<MapleCharacter> affectedp = new ArrayList<MapleCharacter>(affecteds.size()); for (MapleMapObject affectedmo : affecteds) { MapleCharacter affected = (MapleCharacter) affectedmo; if (affected != applyfrom && (isGmBuff() || applyfrom.getParty().equals(affected.getParty()))) { if ((isResurrection() && !affected.isAlive()) || (!isResurrection() && affected.isAlive())) { affectedp.add(affected); } if (isTimeLeap()) { for (PlayerCoolDownValueHolder i : affected.getAllCooldowns()) { affected.removeCooldown(i.skillId); } } } } for (MapleCharacter affected : affectedp) { applyTo(applyfrom, affected, false, null); affected.getClient().getSession().write(MaplePacketCreator.showOwnBuffEffect(sourceid, 2)); affected.getMap().broadcastMessage(affected, MaplePacketCreator.showBuffeffect(affected.getId(), sourceid, 2), false); } } } private void applyMonsterBuff(MapleCharacter applyfrom) { Rectangle bounds = calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft()); List<MapleMapObject> affected = applyfrom.getMap().getMapObjectsInRect(bounds, Arrays.asList(MapleMapObjectType.MONSTER)); ISkill skill_ = SkillFactory.getSkill(sourceid); int i = 0; for (MapleMapObject mo : affected) { MapleMonster monster = (MapleMonster) mo; if (makeChanceResult()) { monster.applyStatus(applyfrom, new MonsterStatusEffect(getMonsterStati(), skill_, null, false), isPoison(), getDuration()); } i++; if (i >= mobCount) { break; } } } private Rectangle calculateBoundingBox(Point posFrom, boolean facingLeft) { Point mylt; Point myrb; if (facingLeft) { mylt = new Point(lt.x + posFrom.x, lt.y + posFrom.y); myrb = new Point(rb.x + posFrom.x, rb.y + posFrom.y); } else { myrb = new Point(-lt.x + posFrom.x, rb.y + posFrom.y); mylt = new Point(-rb.x + posFrom.x, lt.y + posFrom.y); } Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y); return bounds; } public void silentApplyBuff(MapleCharacter chr, long starttime) { int localDuration = duration; localDuration = alchemistModifyVal(chr, localDuration, false); CancelEffectAction cancelAction = new CancelEffectAction(chr, this, starttime); ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - System.currentTimeMillis())); chr.registerEffect(this, starttime, schedule); SummonMovementType summonMovementType = getSummonMovementType(); if (summonMovementType != null) { final MapleSummon tosummon = new MapleSummon(chr, sourceid, chr.getPosition(), summonMovementType); if (!tosummon.isStationary()) { chr.addSummon(sourceid, tosummon); tosummon.addHP(x); } } if (sourceid == Corsair.BATTLE_SHIP) chr.announce(MaplePacketCreator.skillCooldown(5221999, chr.getBattleshipHp())); } public final void applyComboBuff(final MapleCharacter applyto, int combo) { final List<MapleBuffStatDelta> stat = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.ARAN_COMBO, combo)); applyto.getClient().getSession().write(MaplePacketCreator.giveBuff(sourceid, 99999, stat)); final long starttime = System.currentTimeMillis(); // final CancelEffectAction cancelAction = new // CancelEffectAction(applyto, this, starttime); // final ScheduledFuture<?> schedule = // TimerManager.getInstance().schedule(cancelAction, ((starttime + // 99999) - System.currentTimeMillis())); applyto.registerEffect(this, starttime, null); } private void applyBuffEffect(MapleCharacter applyfrom, MapleCharacter applyto, boolean primary) { if (!isMonsterRiding()) applyto.cancelEffect(this, true, -1); List<MapleBuffStatDelta> localstatups = statups; int localDuration = duration; int localsourceid = sourceid; int seconds = localDuration / 1000; MapleMount givemount = null; if (isMonsterRiding()) { int ridingLevel = 0; IItem mount = applyfrom.getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -18); if (mount != null) { ridingLevel = mount.getItemId(); } if (sourceid == Corsair.BATTLE_SHIP) { ridingLevel = 1932000; } else if (sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP) { ridingLevel = 1932000 + applyto.getSkillLevel(sourceid); } else if (sourceid == Beginner.YETI_MOUNT1 || sourceid == Noblesse.YETI_MOUNT1 || sourceid == Legend.YETI_MOUNT1) { ridingLevel = 1932003; } else if (sourceid == Beginner.YETI_MOUNT2 || sourceid == Noblesse.YETI_MOUNT2 || sourceid == Legend.YETI_MOUNT2) { ridingLevel = 1932004; } else if (sourceid == Beginner.WITCH_BROOMSTICK || sourceid == Noblesse.WITCH_BROOMSTICK || sourceid == Legend.WITCH_BROOMSTICK) { ridingLevel = 1932005; } else if (sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.BALROG_MOUNT) { ridingLevel = 1932010; } else { if (applyto.getMount() == null) { applyto.mount(ridingLevel, sourceid); } applyto.getMount().startSchedule(); } if (sourceid == Corsair.BATTLE_SHIP) { givemount = new MapleMount(applyto, 1932000, sourceid); } else if (sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP) { givemount = new MapleMount(applyto, 1932000 + applyto.getSkillLevel(sourceid), sourceid); } else if (sourceid == Beginner.YETI_MOUNT1 || sourceid == Noblesse.YETI_MOUNT1 || sourceid == Legend.YETI_MOUNT1) { givemount = new MapleMount(applyto, 1932003, sourceid); } else if (sourceid == Beginner.YETI_MOUNT2 || sourceid == Noblesse.YETI_MOUNT2 || sourceid == Legend.YETI_MOUNT2) { givemount = new MapleMount(applyto, 1932004, sourceid); } else if (sourceid == Beginner.WITCH_BROOMSTICK || sourceid == Noblesse.WITCH_BROOMSTICK || sourceid == Legend.WITCH_BROOMSTICK) { givemount = new MapleMount(applyto, 1932005, sourceid); } else if (sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.BALROG_MOUNT) { givemount = new MapleMount(applyto, 1932010, sourceid); } else { givemount = applyto.getMount(); } localDuration = sourceid; localsourceid = ridingLevel; localstatups = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.MONSTER_RIDING, 0)); } else if (isSkillMorph()) { localstatups = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.MORPH, getMorph(applyto))); } if (primary) { localDuration = alchemistModifyVal(applyfrom, localDuration, false); applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.showBuffeffect(applyto.getId(), sourceid, 1, (byte) 3), false); } if (localstatups.size() > 0) { MaplePacket buff = null; MaplePacket mbuff = null; if (getSummonMovementType() == null) buff = MaplePacketCreator.giveBuff((skill ? sourceid : -sourceid), localDuration, localstatups); if (isDash()) { buff = MaplePacketCreator.givePirateBuff(statups, sourceid, seconds); mbuff = MaplePacketCreator.giveForeignDash(applyto.getId(), sourceid, seconds, localstatups); } else if (isInfusion()) { buff = MaplePacketCreator.givePirateBuff(statups, sourceid, seconds); mbuff = MaplePacketCreator.giveForeignInfusion(applyto.getId(), x, localDuration); } else if (isDs()) { List<MapleBuffStatDelta> dsstat = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.DARKSIGHT, 0)); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat); } else if (isCombo()) { mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), statups); } else if (isMonsterRiding()) { buff = MaplePacketCreator.giveBuff(localsourceid, localDuration, localstatups); mbuff = MaplePacketCreator.showMonsterRiding(applyto.getId(), givemount); localDuration = duration; if (sourceid == Corsair.BATTLE_SHIP) {// hp if (applyto.getBattleshipHp() == 0) applyto.resetBattleshipHp(); } } else if (isShadowPartner()) { List<MapleBuffStatDelta> stat = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.SHADOWPARTNER, 0)); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), stat); } else if (isSoulArrow()) { List<MapleBuffStatDelta> stat = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.SOULARROW, 0)); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), stat); } else if (isEnrage()) { applyto.handleOrbconsume(); } else if (isMorph()) { List<MapleBuffStatDelta> stat = Collections.singletonList(new MapleBuffStatDelta(MapleBuffStat.MORPH, getMorph(applyto))); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), stat); } else if (isTimeLeap()) { for (PlayerCoolDownValueHolder i : applyto.getAllCooldowns()) { if (i.skillId != Buccaneer.TIME_LEAP) { applyto.removeCooldown(i.skillId); } } } long starttime = System.currentTimeMillis(); CancelEffectAction cancelAction = new CancelEffectAction(applyto, this, starttime); ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, localDuration); applyto.registerEffect(this, starttime, schedule); if (buff != null) applyto.getClient().getSession().write(buff); if (mbuff != null) applyto.getMap().broadcastMessage(applyto, mbuff, false); if (sourceid == Corsair.BATTLE_SHIP) applyto.announce(MaplePacketCreator.skillCooldown(5221999, applyto.getBattleshipHp() / 10)); } } private int calcHPChange(MapleCharacter applyfrom, boolean primary) { int hpchange = 0; if (hp != 0) { if (!skill) { if (primary) { hpchange += alchemistModifyVal(applyfrom, hp, true); } else { hpchange += hp; } } else { hpchange += makeHealHP(hp / 100.0, applyfrom.getTotalMagic(), 3, 5); } } if (hpR != 0) { hpchange += (int) (applyfrom.getCurrentMaxHp() * hpR); applyfrom.checkBerserk(); } if (primary) { if (hpCon != 0) { hpchange -= hpCon; } } if (isChakra()) { hpchange += makeHealHP(getY() / 100.0, applyfrom.getTotalLuk(), 2.3, 3.5); } else if (sourceid == SuperGM.HEAL_PLUS_DISPEL) hpchange += (applyfrom.getMaxHp() - applyfrom.getHp()); return hpchange; } private int makeHealHP(double rate, double stat, double lowerfactor, double upperfactor) { return (int) ((Math.random() * ((int) (stat * upperfactor * rate) - (int) (stat * lowerfactor * rate) + 1)) + (int) (stat * lowerfactor * rate)); } private int calcMPChange(MapleCharacter applyfrom, boolean primary) { int mpchange = 0; if (mp != 0) { if (primary) { mpchange += alchemistModifyVal(applyfrom, mp, true); } else { mpchange += mp; } } if (mpR != 0) { mpchange += (int) (applyfrom.getCurrentMaxMp() * mpR); } if (primary) { if (mpCon != 0) { double mod = 1.0; boolean isAFpMage = applyfrom.getJob().isA(MapleJob.FP_MAGE); boolean isCygnus = applyfrom.getJob().isA(MapleJob.BLAZEWIZARD2); if (isAFpMage || isCygnus || applyfrom.getJob().isA(MapleJob.IL_MAGE)) { ISkill amp = isAFpMage ? SkillFactory.getSkill(FPMage.ELEMENT_AMPLIFICATION) : (isCygnus ? SkillFactory.getSkill(BlazeWizard.ELEMENT_AMPLIFICATION) : SkillFactory.getSkill(ILMage.ELEMENT_AMPLIFICATION)); int ampLevel = applyfrom.getSkillLevel(amp); if (ampLevel > 0) { mod = amp.getEffect(ampLevel).getX() / 100.0; } } mpchange -= mpCon * mod; if (applyfrom.getBuffedValue(MapleBuffStat.INFINITY) != null) { mpchange = 0; } else if (applyfrom.getBuffedValue(MapleBuffStat.CONCENTRATE) != null) { mpchange -= (int) (mpchange * (applyfrom.getBuffedValue(MapleBuffStat.CONCENTRATE).doubleValue() / 100)); } } } if (sourceid == SuperGM.HEAL_PLUS_DISPEL) mpchange += (applyfrom.getMaxMp() - applyfrom.getMp()); return mpchange; } private int alchemistModifyVal(MapleCharacter chr, int val, boolean withX) { if (!skill && (chr.getJob().isA(MapleJob.HERMIT) || chr.getJob().isA(MapleJob.NIGHTWALKER3))) { MapleStatEffect alchemistEffect = getAlchemistEffect(chr); if (alchemistEffect != null) { return (int) (val * ((withX ? alchemistEffect.getX() : alchemistEffect.getY()) / 100.0)); } } return val; } private MapleStatEffect getAlchemistEffect(MapleCharacter chr) { int id = Hermit.ALCHEMIST; if (chr.isCygnus()) { id = NightWalker.ALCHEMIST; } int alchemistLevel = chr.getSkillLevel(SkillFactory.getSkill(id)); return alchemistLevel == 0 ? null : SkillFactory.getSkill(id).getEffect(alchemistLevel); } private boolean isGmBuff() { switch (sourceid) { case Beginner.ECHO_OF_HERO: case Noblesse.ECHO_OF_HERO: case Legend.ECHO_OF_HERO: case SuperGM.HEAL_PLUS_DISPEL: case SuperGM.HASTE: case SuperGM.HOLY_SYMBOL: case SuperGM.BLESS: case SuperGM.RESURRECTION: case SuperGM.HYPER_BODY: return true; default: return false; } } private boolean isMonsterBuff() { if (!skill) { return false; } switch (sourceid) { case Page.THREATEN: case FPWizard.SLOW: case ILWizard.SLOW: case FPMage.SEAL: case ILMage.SEAL: case Priest.DOOM: case Hermit.SHADOW_WEB: case NightLord.NINJA_AMBUSH: case Shadower.NINJA_AMBUSH: case BlazeWizard.SLOW: case BlazeWizard.SEAL: case NightWalker.SHADOW_WEB: return true; } return false; } private boolean isPartyBuff() { if (lt == null || rb == null) { return false; } if ((sourceid >= 1211003 && sourceid <= 1211008) || sourceid == Paladin.SWORD_HOLY_CHARGE || sourceid == Paladin.BW_HOLY_CHARGE || sourceid == DawnWarrior.SOUL_CHARGE) {// wk // charges // have // lt // and // rb // set // but // are // neither // player // nor // monster // buffs return false; } return true; } private boolean isHeal() { return sourceid == Cleric.HEAL || sourceid == SuperGM.HEAL_PLUS_DISPEL; } private boolean isResurrection() { return sourceid == Bishop.RESURRECTION || sourceid == GM.RESURRECTION || sourceid == SuperGM.RESURRECTION; } private boolean isTimeLeap() { return sourceid == Buccaneer.TIME_LEAP; } public boolean isDragonBlood() { return skill && sourceid == DragonKnight.DRAGON_BLOOD; } public boolean isBerserk() { return skill && sourceid == DarkKnight.BERSERK; } public boolean isRecovery() { return sourceid == Beginner.RECOVERY || sourceid == Noblesse.RECOVERY || sourceid == Legend.RECOVERY; } private boolean isDs() { return skill && (sourceid == Rogue.DARK_SIGHT || sourceid == WindArcher.WIND_WALK || sourceid == NightWalker.DARK_SIGHT); } private boolean isCombo() { return skill && (sourceid == Crusader.COMBO || sourceid == DawnWarrior.COMBO); } private boolean isEnrage() { return skill && sourceid == Hero.ENRAGE; } public boolean isBeholder() { return skill && sourceid == DarkKnight.BEHOLDER; } private boolean isShadowPartner() { return skill && (sourceid == Hermit.SHADOW_PARTNER || sourceid == NightWalker.SHADOW_PARTNER); } private boolean isChakra() { return skill && sourceid == ChiefBandit.CHAKRA; } public boolean isMonsterRiding() { return skill && (sourceid % 10000000 == 1004 || sourceid == Corsair.BATTLE_SHIP || sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP || sourceid == Beginner.YETI_MOUNT1 || sourceid == Beginner.YETI_MOUNT2 || sourceid == Beginner.WITCH_BROOMSTICK || sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.YETI_MOUNT1 || sourceid == Noblesse.YETI_MOUNT2 || sourceid == Noblesse.WITCH_BROOMSTICK || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.YETI_MOUNT1 || sourceid == Legend.YETI_MOUNT2 || sourceid == Legend.WITCH_BROOMSTICK || sourceid == Legend.BALROG_MOUNT); } public boolean isMagicDoor() { return skill && sourceid == Priest.MYSTIC_DOOR; } public boolean isPoison() { return skill && (sourceid == FPMage.POISON_MIST || sourceid == FPWizard.POISON_BREATH || sourceid == FPMage.ELEMENT_COMPOSITION || sourceid == NightWalker.POISON_BOMB); } private boolean isMist() { return skill && (sourceid == FPMage.POISON_MIST || sourceid == Shadower.SMOKE_SCREEN || sourceid == BlazeWizard.FLAME_GEAR || sourceid == NightWalker.POISON_BOMB); } private boolean isSoulArrow() { return skill && (sourceid == Hunter.SOUL_ARROW || sourceid == Crossbowman.SOUL_ARROW || sourceid == WindArcher.SOUL_ARROW); } private boolean isShadowClaw() { return skill && sourceid == NightLord.SHADOW_STARS; } private boolean isDispel() { return skill && (sourceid == Priest.DISPEL || sourceid == SuperGM.HEAL_PLUS_DISPEL); } private boolean isHeroWill() { if (skill) { switch (sourceid) { case Hero.HEROS_WILL: case Paladin.HEROS_WILL: case DarkKnight.HEROS_WILL: case FPArchMage.HEROS_WILL: case ILArchMage.HEROS_WILL: case Bishop.HEROS_WILL: case Bowmaster.HEROS_WILL: case Marksman.HEROS_WILL: case NightLord.HEROS_WILL: case Shadower.HEROS_WILL: case Buccaneer.PIRATES_RAGE: case Aran.HEROS_WILL: return true; default: return false; } } return false; } private boolean isDash() { return skill && (sourceid == Pirate.DASH || sourceid == ThunderBreaker.DASH || sourceid == Beginner.SPACE_DASH || sourceid == Noblesse.SPACE_DASH); } private boolean isSkillMorph() { return skill && (sourceid == Buccaneer.SUPER_TRANSFORMATION || sourceid == Marauder.TRANSFORMATION || sourceid == WindArcher.EAGLE_EYE || sourceid == ThunderBreaker.TRANSFORMATION); } private boolean isInfusion() { return skill && (sourceid == Buccaneer.SPEED_INFUSION || sourceid == Corsair.SPEED_INFUSION || sourceid == ThunderBreaker.SPEED_INFUSION); } private boolean isCygnusFA() { return skill && (sourceid == DawnWarrior.FINAL_ATTACK || sourceid == WindArcher.FINAL_ATTACK); } private boolean isMorph() { return morphId > 0; } private boolean isComboReset() { return sourceid == Aran.COMBO_BARRIER || sourceid == Aran.COMBO_DRAIN; } private int getFatigue() { return fatigue; } private int getMorph() { return morphId; } private int getMorph(MapleCharacter chr) { if (morphId % 10 == 0) { return morphId + chr.getGender(); } return morphId + 100 * chr.getGender(); } private SummonMovementType getSummonMovementType() { if (!skill) { return null; } switch (sourceid) { case Ranger.PUPPET: case Sniper.PUPPET: case WindArcher.PUPPET: case Outlaw.OCTOPUS: case Corsair.WRATH_OF_THE_OCTOPI: return SummonMovementType.STATIONARY; case Ranger.SILVER_HAWK: case Sniper.GOLDEN_EAGLE: case Priest.SUMMON_DRAGON: case Marksman.FROST_PREY: case Bowmaster.PHOENIX: case Outlaw.GAVIOTA: return SummonMovementType.CIRCLE_FOLLOW; case DarkKnight.BEHOLDER: case FPArchMage.ELQUINES: case ILArchMage.IFRIT: case Bishop.BAHAMUT: case DawnWarrior.SOUL: case BlazeWizard.FLAME: case BlazeWizard.IFRIT: case WindArcher.STORM: case NightWalker.DARKNESS: case ThunderBreaker.LIGHTNING: return SummonMovementType.FOLLOW; } return null; } public boolean isSkill() { return skill; } public int getSourceId() { return sourceid; } public boolean makeChanceResult() { return prop == 1.0 || Math.random() < prop; } private static class CancelEffectAction implements Runnable { private MapleStatEffect effect; private WeakReference<MapleCharacter> target; private long startTime; public CancelEffectAction(MapleCharacter target, MapleStatEffect effect, long startTime) { this.effect = effect; this.target = new WeakReference<MapleCharacter>(target); this.startTime = startTime; } @Override public void run() { MapleCharacter realTarget = target.get(); if (realTarget != null) { realTarget.cancelEffect(effect, false, startTime); } } } public short getHp() { return hp; } public short getMp() { return mp; } public short getHpCon() { return hpCon; } public short getMpCon() { return mpCon; } public short getMatk() { return matk; } public int getDuration() { return duration; } public List<MapleBuffStatDelta> getStatups() { return statups; } public boolean sameSource(MapleStatEffect effect) { return this.sourceid == effect.sourceid && this.skill == effect.skill; } public int getX() { return x; } public int getY() { return y; } public int getDamage() { return damage; } public int getAttackCount() { return attackCount; } public int getMobCount() { return mobCount; } public int getFixDamage() { return fixdamage; } public byte getBulletCount() { return bulletCount; } public byte getBulletConsume() { return bulletConsume; } public int getMoneyCon() { return moneyCon; } public int getCooldown() { return cooldown; } public boolean getRepeatEffect() { return repeatEffect; } public Map<MonsterStatus, Integer> getMonsterStati() { return monsterStatus; } }