MapleStatEffect.java
上传用户:gwt600
上传日期:2021-06-03
资源大小:704k
文件大小:55k
源码类别:

游戏

开发平台:

Java

  1. /*
  2. This file is part of the OdinMS Maple Story Server
  3. Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
  4. Matthias Butz <matze@odinms.de>
  5. Jan Christian Meyer <vimes@odinms.de>
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU Affero General Public License version 3
  8. as published by the Free Software Foundation. You may not use, modify
  9. or distribute this program under any other version of the
  10. GNU Affero General Public License.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU Affero General Public License for more details.
  15. You should have received a copy of the GNU Affero General Public License
  16. along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18. /*
  19.  * ItemEndEffect.java
  20.  *
  21.  * Created on 29. November 2007, 01:34
  22.  */
  23. package net.sf.odinms.server;
  24. import java.awt.Point;
  25. import java.awt.Rectangle;
  26. import java.io.Serializable;
  27. import java.lang.ref.WeakReference;
  28. import java.util.ArrayList;
  29. import java.util.Arrays;
  30. import java.util.Collections;
  31. import java.util.List;
  32. import java.util.Map;
  33. import java.util.concurrent.ScheduledFuture;
  34. import net.sf.odinms.client.IItem;
  35. import net.sf.odinms.client.ISkill;
  36. import net.sf.odinms.client.MapleBuffStat;
  37. import net.sf.odinms.client.MapleCharacter;
  38. import net.sf.odinms.client.MapleDisease;
  39. import net.sf.odinms.client.MapleMount;
  40. import net.sf.odinms.client.MapleInventory;
  41. import net.sf.odinms.client.MapleInventoryType;
  42. import net.sf.odinms.client.MapleJob;
  43. import net.sf.odinms.client.MapleStat;
  44. import net.sf.odinms.client.SkillFactory;
  45. import net.sf.odinms.client.status.MonsterStatus;
  46. import net.sf.odinms.client.status.MonsterStatusEffect;
  47. import net.sf.odinms.net.channel.ChannelServer;
  48. import net.sf.odinms.provider.MapleData;
  49. import net.sf.odinms.provider.MapleDataTool;
  50. import net.sf.odinms.server.life.MapleMonster;
  51. import net.sf.odinms.server.maps.MapleDoor;
  52. import net.sf.odinms.server.maps.MapleMap;
  53. import net.sf.odinms.server.maps.MapleMapObject;
  54. import net.sf.odinms.server.maps.MapleMapObjectType;
  55. import net.sf.odinms.server.maps.MapleMist;
  56. import net.sf.odinms.server.maps.MapleSummon;
  57. import net.sf.odinms.server.maps.SummonMovementType;
  58. import net.sf.odinms.net.world.PlayerCoolDownValueHolder;
  59. import net.sf.odinms.net.MaplePacket;
  60. import net.sf.odinms.tools.ArrayMap;
  61. import net.sf.odinms.tools.MaplePacketCreator;
  62. import net.sf.odinms.tools.Pair;
  63. /**
  64.  * @author Matze
  65.  * @author Frz
  66.  */
  67. public class MapleStatEffect implements Serializable {
  68.     static final long serialVersionUID = 9179541993413738569L;
  69.     private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MapleStatEffect.class);
  70.     private short watk,  matk,  wdef,  mdef,  acc,  avoid,  hands,  speed,  jump;
  71.     private short hp,  mp;
  72.     private double hpR,  mpR;
  73.     private short mpCon,  hpCon;
  74.     private int duration;
  75.     private boolean overTime;
  76.     private int sourceid;
  77.     private int moveTo;
  78.     private boolean skill;
  79.     private List<Pair<MapleBuffStat, Integer>> statups;
  80.     private Map<MonsterStatus, Integer> monsterStatus;
  81.     private int x,  y,  z;
  82.     private double prop;
  83.     private int iProp;
  84.     private int itemCon,  itemConNo;
  85.     private int damage,  attackCount,  bulletCount,  bulletConsume;
  86.     private Point lt,  rb;
  87.     private int mobCount;
  88.     private int moneyCon;
  89.     private int cooldown;
  90.     private boolean isMorph = false;
  91.     private int morphId = 0;
  92.     private List<MapleDisease> cureDebuffs;
  93.     private int mastery,  range;
  94.     public MapleStatEffect() {
  95.     }
  96.     public static MapleStatEffect loadSkillEffectFromData(MapleData source, int skillid, boolean overtime) {
  97.         return loadFromData(source, skillid, true, overtime);
  98.     }
  99.     public static MapleStatEffect loadItemEffectFromData(MapleData source, int itemid) {
  100.         return loadFromData(source, itemid, false, false);
  101.     }
  102.     private static void addBuffStatPairToListIfNotZero(List<Pair<MapleBuffStat, Integer>> list, MapleBuffStat buffstat, Integer val) {
  103.         if (val.intValue() != 0) {
  104.             list.add(new Pair<MapleBuffStat, Integer>(buffstat, val));
  105.         }
  106.     }
  107.     private static MapleStatEffect loadFromData(MapleData source, int sourceid, boolean skill, boolean overTime) {
  108.         MapleStatEffect ret = new MapleStatEffect();
  109.         ret.duration = MapleDataTool.getIntConvert("time", source, -1);
  110.         ret.hp = (short) MapleDataTool.getInt("hp", source, 0);
  111.         ret.hpR = MapleDataTool.getInt("hpR", source, 0) / 100.0;
  112.         ret.mp = (short) MapleDataTool.getInt("mp", source, 0);
  113.         ret.mpR = MapleDataTool.getInt("mpR", source, 0) / 100.0;
  114.         ret.mpCon = (short) MapleDataTool.getInt("mpCon", source, 0);
  115.         ret.hpCon = (short) MapleDataTool.getInt("hpCon", source, 0);
  116.         ret.iProp = MapleDataTool.getInt("prop", source, 100);
  117.         ret.prop = ret.iProp / 100.0;
  118.         ret.mobCount = MapleDataTool.getInt("mobCount", source, 1);
  119.         ret.cooldown = MapleDataTool.getInt("cooltime", source, 0);
  120.         ret.morphId = MapleDataTool.getInt("morph", source, 0);
  121.         ret.isMorph = ret.morphId > 0 ? true : false;
  122.         ret.sourceid = sourceid;
  123.         ret.skill = skill;
  124.         if (!ret.skill && ret.duration > -1) {
  125.             ret.overTime = true;
  126.         } else {
  127.             ret.duration *= 1000; // items have their times stored in ms, of course
  128.             ret.overTime = overTime;
  129.         }
  130.         ArrayList<Pair<MapleBuffStat, Integer>> statups = new ArrayList<Pair<MapleBuffStat, Integer>>();
  131.         ret.watk = (short) MapleDataTool.getInt("pad", source, 0);
  132.         ret.wdef = (short) MapleDataTool.getInt("pdd", source, 0);
  133.         ret.matk = (short) MapleDataTool.getInt("mad", source, 0);
  134.         ret.mdef = (short) MapleDataTool.getInt("mdd", source, 0);
  135.         ret.acc = (short) MapleDataTool.getIntConvert("acc", source, 0);
  136.         ret.avoid = (short) MapleDataTool.getInt("eva", source, 0);
  137.         ret.speed = (short) MapleDataTool.getInt("speed", source, 0);
  138.         ret.jump = (short) MapleDataTool.getInt("jump", source, 0);
  139.         if (ret.overTime && ret.getSummonMovementType() == null) {
  140.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WATK, Integer.valueOf(ret.watk));
  141.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.WDEF, Integer.valueOf(ret.wdef));
  142.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MATK, Integer.valueOf(ret.matk));
  143.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MDEF, Integer.valueOf(ret.mdef));
  144.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.ACC, Integer.valueOf(ret.acc));
  145.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.AVOID, Integer.valueOf(ret.avoid));
  146.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.SPEED, Integer.valueOf(ret.speed));
  147.             addBuffStatPairToListIfNotZero(statups, MapleBuffStat.JUMP, Integer.valueOf(ret.jump));
  148.         }
  149.         MapleData ltd = source.getChildByPath("lt");
  150.         if (ltd != null) {
  151.             ret.lt = (Point) ltd.getData();
  152.             ret.rb = (Point) source.getChildByPath("rb").getData();
  153.         }
  154.         int x = MapleDataTool.getInt("x", source, 0);
  155.         ret.x = x;
  156.         ret.y = MapleDataTool.getInt("y", source, 0);
  157.         ret.z = MapleDataTool.getInt("z", source, 0);
  158.         ret.damage = MapleDataTool.getIntConvert("damage", source, 100);
  159.         ret.attackCount = MapleDataTool.getIntConvert("attackCount", source, 1);
  160.         ret.bulletCount = MapleDataTool.getIntConvert("bulletCount", source, 1);
  161.         ret.bulletConsume = MapleDataTool.getIntConvert("bulletConsume", source, 0);
  162.         ret.moneyCon = MapleDataTool.getIntConvert("moneyCon", source, 0);
  163.         ret.mastery = MapleDataTool.getIntConvert("mastery", source, 0);
  164.         ret.range = MapleDataTool.getIntConvert("range", source, 0);
  165.         ret.itemCon = MapleDataTool.getInt("itemCon", source, 0);
  166.         ret.itemConNo = MapleDataTool.getInt("itemConNo", source, 0);
  167.         ret.moveTo = MapleDataTool.getInt("moveTo", source, -1);
  168.         List<MapleDisease> localCureDebuffs = new ArrayList<MapleDisease>();
  169.         if (MapleDataTool.getInt("poison", source, 0) > 0) {
  170.             localCureDebuffs.add(MapleDisease.POISON);
  171.         }
  172.         if (MapleDataTool.getInt("seal", source, 0) > 0) {
  173.             localCureDebuffs.add(MapleDisease.SEAL);
  174.         }
  175.         if (MapleDataTool.getInt("darkness", source, 0) > 0) {
  176.             localCureDebuffs.add(MapleDisease.DARKNESS);
  177.         }
  178.         if (MapleDataTool.getInt("weakness", source, 0) > 0) {
  179.             localCureDebuffs.add(MapleDisease.WEAKEN);
  180.         }
  181.         if (MapleDataTool.getInt("curse", source, 0) > 0) {
  182.             localCureDebuffs.add(MapleDisease.CURSE);
  183.         }
  184.         ret.cureDebuffs = localCureDebuffs;
  185.         Map<MonsterStatus, Integer> monsterStatus = new ArrayMap<MonsterStatus, Integer>();
  186.         if (skill) { // hack because we can't get from the datafile...
  187.             switch (sourceid) {
  188.                 case 2001002: // magic guard
  189.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MAGIC_GUARD, Integer.valueOf(x)));
  190.                     break;
  191.                 case 2301003: // invincible
  192.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.INVINCIBLE, Integer.valueOf(x)));
  193.                     break;
  194.                 case 9101004: // hide
  195.                     ret.duration = 60 * 120 * 1000;
  196.                     ret.overTime = true;
  197.                 case 4001003: // darksight
  198.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DARKSIGHT, Integer.valueOf(x)));
  199.                     break;
  200.                 case 4211003: // pickpocket
  201.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.PICKPOCKET, Integer.valueOf(x)));
  202.                     break;
  203.                 case 4211005: // mesoguard
  204.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MESOGUARD, Integer.valueOf(x)));
  205.                     break;
  206.                 case 4111001: // mesoup
  207.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MESOUP, Integer.valueOf(x)));
  208.                     break;
  209.                 case 4111002: // shadowpartner
  210.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SHADOWPARTNER, Integer.valueOf(x)));
  211.                     break;
  212.                 case 3101004: // soul arrow
  213.                 case 3201004:
  214.                 case 2311002: // mystic door - hacked buff icon
  215.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SOULARROW, Integer.valueOf(x)));
  216.                     break;
  217.                 case 1211003:
  218.                 case 1211004:
  219.                 case 1211005:
  220.                 case 1211006: // wk charges
  221.                 case 1211007:
  222.                 case 1211008:
  223.                 case 1221003:
  224.                 case 1221004:
  225.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WK_CHARGE, Integer.valueOf(x)));
  226.                     break;
  227.                 case 1101004:
  228.                 case 1101005: // booster
  229.                 case 1201004:
  230.                 case 1201005:
  231.                 case 1301004:
  232.                 case 1301005:
  233.                 case 2111005: // spell booster, do these work the same?
  234.                 case 2211005:
  235.                 case 3101002:
  236.                 case 3201002:
  237.                 case 4101003:
  238.                 case 4201002:
  239.                 case 5101006:
  240.                 case 5201003:
  241.                 case 5221010: // speed infusion
  242.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.BOOSTER, Integer.valueOf(x)));
  243.                     break;
  244.                 case 1101006: // rage
  245.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WDEF, Integer.valueOf(ret.wdef)));
  246.                 case 1121010: // enrage
  247.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WATK, Integer.valueOf(ret.watk)));
  248.                     break;
  249.                 case 1301006: // iron will
  250.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MDEF, Integer.valueOf(ret.mdef)));
  251.                 case 1001003: // iron body
  252.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WDEF, Integer.valueOf(ret.wdef)));
  253.                     break;
  254.                 case 2001003: // magic armor
  255.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WDEF, Integer.valueOf(ret.wdef)));
  256.                     break;
  257.                 case 2101001: // meditation
  258.                 case 2201001: // meditation
  259.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MATK, Integer.valueOf(ret.matk)));
  260.                     break;
  261.                 case 4101004: // haste
  262.                 case 4201003: // haste
  263.                 case 9101001: // gm haste
  264.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SPEED, Integer.valueOf(ret.speed)));
  265.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.JUMP, Integer.valueOf(ret.jump)));
  266.                     break;
  267.                 case 2301004: // bless
  268.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WDEF, Integer.valueOf(ret.wdef)));
  269.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MDEF, Integer.valueOf(ret.mdef)));
  270.                 case 3001003: // focus
  271.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.ACC, Integer.valueOf(ret.acc)));
  272.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.AVOID, Integer.valueOf(ret.avoid)));
  273.                     break;
  274.                 case 9101003: // gm bless
  275.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MATK, Integer.valueOf(ret.matk)));
  276.                 case 3121008: // concentrate
  277.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.WATK, Integer.valueOf(ret.watk)));
  278.                     break;
  279.                      case 5001005: // Dash
  280.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DASH, Integer.valueOf(1)));
  281.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SPEED, Integer.valueOf(ret.x)));
  282.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.JUMP, Integer.valueOf(ret.y)));
  283.                     break;
  284.                 case 1101007: // pguard
  285.                 case 1201007:
  286.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.POWERGUARD, Integer.valueOf(x)));
  287.                     break;
  288.                 case 1301007:
  289.                 case 9101008:
  290.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.HYPERBODYHP, Integer.valueOf(x)));
  291.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.HYPERBODYMP, Integer.valueOf(ret.y)));
  292.                     break;
  293.                 case 1001: // recovery
  294.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.RECOVERY, Integer.valueOf(x)));
  295.                     break;
  296.                 case 1111002: // combo
  297.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.COMBO, Integer.valueOf(1)));
  298.                     break;
  299.                 case 1004: // monster riding
  300.                 case 5221006: // 4th Job - Pirate riding
  301.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MONSTER_RIDING, Integer.valueOf(1)));
  302.                     break;
  303.                 case 1311006: //dragon roar
  304.                     ret.hpR = -x / 100.0;
  305.                     break;
  306.                 case 1311008: // dragon blood
  307.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DRAGONBLOOD, Integer.valueOf(ret.x)));
  308.                     break;
  309.                 case 1121000: // maple warrior, all classes
  310.                 case 1221000:
  311.                 case 1321000:
  312.                 case 2121000:
  313.                 case 2221000:
  314.                 case 2321000:
  315.                 case 3121000:
  316.                 case 3221000:
  317.                 case 4121000:
  318.                 case 4221000:
  319.                 case 5121000:
  320.                 case 5221000:
  321.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MAPLE_WARRIOR, Integer.valueOf(ret.x)));
  322.                     break;
  323.                 case 3121002: // sharp eyes bow master
  324.                 case 3221002: // sharp eyes marksmen
  325.                     // hack much (TODO is the order correct?)
  326.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SHARP_EYES, Integer.valueOf(ret.x << 8 | ret.y)));
  327.                     break;
  328.                 case 1321007: // Beholder
  329.                 case 2221005: // ifrit
  330.                 case 2311006: // summon dragon
  331.                 case 2321003: // bahamut
  332.                 case 3121006: // phoenix
  333.                 case 5211001: // Pirate octopus summon
  334.                 case 5211002: // Pirate bird summon
  335.                 case 5220002: // wrath of the octopi
  336.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SUMMON, Integer.valueOf(1)));
  337.                     break;
  338.                 case 2311003: // hs
  339.                 case 9101002: // GM hs
  340.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.HOLY_SYMBOL, Integer.valueOf(x)));
  341.                     break;
  342.                 case 4121006: // spirit claw
  343.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SHADOW_CLAW, Integer.valueOf(0)));
  344.                     break;
  345.                 case 2121004:
  346.                 case 2221004:
  347.                 case 2321004: // Infinity
  348.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.INFINITY, Integer.valueOf(x)));
  349.                     break;
  350.                 case 1121002:
  351.                 case 1221002:
  352.                 case 1321002: // Stance
  353.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.STANCE, Integer.valueOf(ret.iProp)));
  354.                     break;
  355.                 case 1005: // Echo of Hero
  356.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.ECHO_OF_HERO, Integer.valueOf(ret.x)));
  357.                     break;
  358.                 case 2121002: // mana reflection
  359.                 case 2221002:
  360.                 case 2321002:
  361.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MANA_REFLECTION, Integer.valueOf(1)));
  362.                     break;
  363.                 case 2321005: // holy shield
  364.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.HOLY_SHIELD, Integer.valueOf(x)));
  365.                     break;
  366.                 case 3111002: // puppet ranger
  367.                 case 3211002: // puppet sniper
  368.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.PUPPET, Integer.valueOf(1)));
  369.                     break;
  370.                 // ----------------------------- MONSTER STATUS PUT! ----------------------------- //
  371.                 case 4001002: // disorder
  372.                     monsterStatus.put(MonsterStatus.WATK, Integer.valueOf(ret.x));
  373.                     monsterStatus.put(MonsterStatus.WDEF, Integer.valueOf(ret.y));
  374.                     break;
  375.                 case 1201006: // threaten
  376.                     monsterStatus.put(MonsterStatus.WATK, Integer.valueOf(ret.x));
  377.                     monsterStatus.put(MonsterStatus.WDEF, Integer.valueOf(ret.y));
  378.                     break;
  379.                 case 1111005: // coma: sword
  380.                 case 1111006: // coma: axe
  381.                 case 1111008: // shout
  382.                 case 1211002: // charged blow
  383.                 case 3101005: // arrow bomb
  384.                 case 4211002: // assaulter
  385.                 case 4221007: // boomerang step
  386.                 case 5101002: // Backspin Blow
  387.                 case 5101003: // Double Uppercut
  388.                 case 5121004: // pirate 8 hit punches
  389.                 case 5121005: // pirate pull mob skill? O.o
  390.                 case 5121007: // pirate 6 hit shyt...
  391.                 case 5201004: // pirate blank shot
  392.                     monsterStatus.put(MonsterStatus.STUN, Integer.valueOf(1));
  393.                     break;
  394.                 case 4121003:
  395.                 case 4221003:
  396.                     monsterStatus.put(MonsterStatus.SHOWDOWN, Integer.valueOf(1));
  397.                     break;
  398.                 case 2201004: // cold beam
  399.                 case 2211002: // ice strike
  400.                 case 2211006: // il elemental compo
  401.                 case 2221007: // Blizzard
  402.                 case 3211003: // blizzard
  403.                 case 5211005:
  404.                     monsterStatus.put(MonsterStatus.FREEZE, Integer.valueOf(1));
  405.                     ret.duration *= 2; // freezing skills are a little strange
  406.                     break;
  407.                 case 2121006://Paralyze
  408.                 case 2101003: // fp slow
  409.                 case 2201003: // il slow
  410.                     monsterStatus.put(MonsterStatus.SPEED, Integer.valueOf(ret.x));
  411.                     break;
  412.                 case 2101005: // poison breath
  413.                 case 2111006: // fp elemental compo
  414.                     monsterStatus.put(MonsterStatus.POISON, Integer.valueOf(1));
  415.                     break;
  416.                 case 2311005:
  417.                     monsterStatus.put(MonsterStatus.DOOM, Integer.valueOf(1));
  418.                     break;
  419.                 case 3111005: // golden hawk
  420.                 case 3211005: // golden eagle
  421.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SUMMON, Integer.valueOf(1)));
  422.                     monsterStatus.put(MonsterStatus.STUN, Integer.valueOf(1));
  423.                     break;
  424.                 case 2121005: // elquines
  425.                 case 3221005: // frostprey
  426.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SUMMON, Integer.valueOf(1)));
  427.                     monsterStatus.put(MonsterStatus.FREEZE, Integer.valueOf(1));
  428.                     break;
  429.                 case 2111004: // fp seal
  430.                 case 2211004: // il seal
  431.                     monsterStatus.put(MonsterStatus.SEAL, 1);
  432.                     break;
  433.                 case 4111003: // shadow web
  434.                     monsterStatus.put(MonsterStatus.SHADOW_WEB, 1);
  435.                     break;
  436.                 case 3121007: // Hamstring
  437.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.HAMSTRING, Integer.valueOf(x)));
  438.                     monsterStatus.put(MonsterStatus.SPEED, x);
  439.                     break;
  440.                 case 3221006: // Blind
  441.                     statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.BLIND, Integer.valueOf(x)));
  442.                     monsterStatus.put(MonsterStatus.ACC, x);
  443.                     break;
  444.                 default:
  445.                 // nothing needs to be added, that's ok
  446.             }
  447.         }
  448.         if (ret.isMorph()) {
  449.             statups.add(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MORPH, Integer.valueOf(ret.getMorph())));
  450.         }
  451.         ret.monsterStatus = monsterStatus;
  452.         // TODO: fixDamage, coolTime
  453.         statups.trimToSize();
  454.         ret.statups = statups;
  455.         return ret;
  456.     }
  457.     /**
  458.      * @param applyto
  459.      * @param obj
  460.      * @param attack damage done by the skill
  461.      */
  462.     public void applyPassive(MapleCharacter applyto, MapleMapObject obj, int attack) {
  463.         if (makeChanceResult()) {
  464.             switch (sourceid) {
  465.                 // MP eater
  466.                 case 2100000:
  467.                 case 2200000:
  468.                 case 2300000:
  469.                     if (obj == null || obj.getType() != MapleMapObjectType.MONSTER) {
  470.                         return;
  471.                     }
  472.                     MapleMonster mob = (MapleMonster) obj;
  473.                     // x is absorb percentage
  474.                     if (!mob.isBoss()) {
  475.                         int absorbMp = Math.min((int) (mob.getMaxMp() * (getX() / 100.0)), mob.getMp());
  476.                         if (absorbMp > 0) {
  477.                             mob.setMp(mob.getMp() - absorbMp);
  478.                             applyto.addMP(absorbMp);
  479.                             applyto.getClient().getSession().write(MaplePacketCreator.showOwnBuffEffect(sourceid, 1));
  480.                             applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.showBuffeffect(applyto.getId(), sourceid, 1, (byte) 3), false);
  481.                         }
  482.                     }
  483.                     break;
  484.             }
  485.         }
  486.     }
  487.     public boolean applyTo(MapleCharacter chr) {
  488.         return applyTo(chr, chr, true, null);
  489.     }
  490.     public boolean applyTo(MapleCharacter chr, Point pos) {
  491.         return applyTo(chr, chr, true, pos);
  492.     }
  493.     private boolean applyTo(MapleCharacter applyfrom, MapleCharacter applyto, boolean primary, Point pos) {
  494.         int hpchange = calcHPChange(applyfrom, primary);
  495.         int mpchange = calcMPChange(applyfrom, primary);
  496.         if (primary) {
  497.             if (itemConNo != 0) {
  498.                 MapleInventoryType type = MapleItemInformationProvider.getInstance().getInventoryType(itemCon);
  499.                 MapleInventoryManipulator.removeById(applyto.getClient(), type, itemCon, itemConNo, false, true);
  500.             }
  501.         }
  502.         if (cureDebuffs.size() > 0) {
  503.             for (MapleDisease debuff : cureDebuffs) {
  504.                 applyfrom.dispelDebuff(debuff);
  505.             }
  506.         }
  507.         List<Pair<MapleStat, Integer>> hpmpupdate = new ArrayList<Pair<MapleStat, Integer>>(2);
  508.         if (!primary && isResurrection()) {
  509.             hpchange = applyto.getMaxHp();
  510.             applyto.setStance(0); //TODO fix death bug, player doesnt spawn on other screen
  511.         }
  512.         //right? wrong? idk..
  513.         if (isDispel() && makeChanceResult()) {
  514.             MonsterStatus[] remove = {MonsterStatus.ACC, MonsterStatus.AVOID, MonsterStatus.WEAPON_IMMUNITY, MonsterStatus.MAGIC_IMMUNITY, MonsterStatus.SPEED};
  515.             for (MapleMapObject _mob : applyfrom.getMap().getMapObjectsInRange(applyfrom.getPosition(), 30000 + applyfrom.getSkillLevel(SkillFactory.getSkill(sourceid)) * 1000, Arrays.asList(MapleMapObjectType.MONSTER))) {
  516.                 MapleMonster mob = (MapleMonster) _mob;
  517.                 if (mob != null && mob.isAlive() && !mob.getMonsterBuffs().isEmpty()) {
  518.                     for (int i = 0; i < remove.length; i++) {
  519.                         if (mob.getMonsterBuffs().contains(remove[i])) {
  520.                             mob.getMonsterBuffs().remove(remove[i]);
  521.                             MaplePacket packet = MaplePacketCreator.cancelMonsterStatus(mob.getObjectId(), Collections.singletonMap(remove[i], Integer.valueOf(1)));
  522.                             mob.getMap().broadcastMessage(packet, mob.getPosition());
  523.                             if (mob.getController() != null && !mob.getController().isMapObjectVisible(mob)) {
  524.                                 mob.getController().getClient().getSession().write(packet);
  525.                             }
  526.                         }
  527.                     }
  528.                 }
  529.             }
  530.             applyto.dispelDebuffs();
  531.         }
  532.         if (isHeroWill()) {
  533.             //applyto.dispelDebuff(MapleDisease.SEDUCE);
  534.             applyto.dispelDebuffs();
  535.         }
  536.         if (hpchange != 0) {
  537.             if (hpchange < 0 && (-hpchange) > applyto.getHp()) {
  538.                 return false;
  539.             }
  540.             int newHp = applyto.getHp() + hpchange;
  541.             if (newHp < 1) {
  542.                 newHp = 1;
  543.             }
  544.             applyto.setHp(newHp);
  545.             hpmpupdate.add(new Pair<MapleStat, Integer>(MapleStat.HP, Integer.valueOf(applyto.getHp())));
  546.         }
  547.         if (mpchange != 0) {
  548.             if (mpchange < 0 && (-mpchange) > applyto.getMp()) {
  549.                 return false;
  550.             }
  551.             applyto.setMp(applyto.getMp() + mpchange);
  552.             hpmpupdate.add(new Pair<MapleStat, Integer>(MapleStat.MP, Integer.valueOf(applyto.getMp())));
  553.         }
  554.         applyto.getClient().getSession().write(MaplePacketCreator.updatePlayerStats(hpmpupdate, true));
  555.         if (moveTo != -1) {
  556.             if (applyto.getMap().getReturnMapId() != applyto.getMapId()) {
  557.                 MapleMap target;
  558.                 if (moveTo == 999999999) {
  559.                     target = applyto.getMap().getReturnMap();
  560.                 } else {
  561.                     target = ChannelServer.getInstance(applyto.getClient().getChannel()).getMapFactory().getMap(moveTo);
  562.                     if (target.getId() / 10000000 != 60 && applyto.getMapId() / 10000000 != 61) {
  563.                         if (target.getId() / 10000000 != 21 && applyto.getMapId() / 10000000 != 20) {
  564.                             if (target.getId() / 10000000 != applyto.getMapId() / 10000000) {
  565.                                 log.info("Player {} is trying to use a return scroll to an illegal location ({}->{})", new Object[]{applyto.getName(), applyto.getMapId(), target.getId()});
  566.                                 applyto.getClient().disconnect();
  567.                                 return false;
  568.                             }
  569.                         }
  570.                     }
  571.                 }
  572.                 applyto.changeMap(target, target.getPortal(0));
  573.             } else {
  574.                 return false;
  575.             }
  576.         }
  577.         if (isShadowClaw()) {
  578.             MapleInventory use = applyto.getInventory(MapleInventoryType.USE);
  579.             MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance();
  580.             int projectile = 0;
  581.             for (int i = 0; i < 255; i++) { // impose order...
  582.                 IItem item = use.getItem((byte) i);
  583.                 if (item != null) {
  584.                     boolean isStar = mii.isThrowingStar(item.getItemId());
  585.                     if (isStar && item.getQuantity() >= 200) {
  586.                         projectile = item.getItemId();
  587.                         break;
  588.                     }
  589.                 }
  590.             }
  591.             if (projectile == 0) {
  592.                 return false;
  593.             } else {
  594.                 MapleInventoryManipulator.removeById(applyto.getClient(), MapleInventoryType.USE, projectile, 200, false, true);
  595.             }
  596.         }
  597.         if (overTime) {
  598.             applyBuffEffect(applyfrom, applyto, primary);
  599.         }
  600.         if (primary && (overTime || isHeal())) {
  601.             applyBuff(applyfrom);
  602.         }
  603.         if (primary && isMonsterBuff()) {
  604.             applyMonsterBuff(applyfrom);
  605.         }
  606.         SummonMovementType summonMovementType = getSummonMovementType();
  607.         if (summonMovementType != null && pos != null) {
  608.             final MapleSummon tosummon = new MapleSummon(applyfrom, sourceid, pos, summonMovementType);
  609.             if (!tosummon.isPuppet()) {
  610.                 applyfrom.getCheatTracker().resetSummonAttack();
  611.             }
  612.             applyfrom.getMap().spawnSummon(tosummon);
  613.             applyfrom.getSummons().put(sourceid, tosummon);
  614.             tosummon.addHP(x);
  615.             if (isBeholder()) {
  616.                 tosummon.addHP(1);
  617.             }
  618.         }
  619.         // Magic Door
  620.         if (isMagicDoor()) {
  621.             //applyto.cancelMagicDoor();
  622.             Point doorPosition = new Point(applyto.getPosition());
  623.             //doorPosition.y -= 280;
  624.             MapleDoor door = new MapleDoor(applyto, doorPosition);
  625.             applyto.getMap().spawnDoor(door);
  626.             applyto.addDoor(door);
  627.             door = new MapleDoor(door);
  628.             applyto.addDoor(door);
  629.             door.getTown().spawnDoor(door);
  630.             if (applyto.getParty() != null) {
  631.                 // update town doors
  632.                 applyto.silentPartyUpdate();
  633.             }
  634.             applyto.disableDoor();
  635.         } else if (isMist()) {
  636.             Rectangle bounds = calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft());
  637.             MapleMist mist = new MapleMist(bounds, applyfrom, this);
  638.             applyfrom.getMap().spawnMist(mist, getDuration(), sourceid == 2111003, false);
  639.         }
  640.         // Time Leap
  641.         if (isTimeLeap()) {
  642.             for (PlayerCoolDownValueHolder i : applyto.getAllCooldowns()) {
  643.                 if (i.skillId != 5121010) {
  644.                     applyto.removeCooldown(i.skillId);
  645.                 }
  646.             }
  647.         }
  648.         return true;
  649.     }
  650.     private void applyBuff(MapleCharacter applyfrom) {
  651.         if (isPartyBuff() && (applyfrom.getParty() != null || isGmBuff())) {
  652.             Rectangle bounds = calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft());
  653.             List<MapleMapObject> affecteds = applyfrom.getMap().getMapObjectsInRect(bounds, Arrays.asList(MapleMapObjectType.PLAYER));
  654.             List<MapleCharacter> affectedp = new ArrayList<MapleCharacter>(affecteds.size());
  655.             for (MapleMapObject affectedmo : affecteds) {
  656.                 MapleCharacter affected = (MapleCharacter) affectedmo;
  657.                 //this is new and weird...
  658.                 if (affected != null && applyfrom == null && isHeal() && affected != applyfrom && affected.getParty() == applyfrom.getParty() && affected.isAlive()) {
  659.                     int expadd = (int) ((calcHPChange(applyfrom, true) / 10) * (applyfrom.getClient().getChannelServer().getExpRate() + ((Math.random() * 10) + 30)) * (Math.floor(Math.random() * (applyfrom.getSkillLevel(SkillFactory.getSkill(2301002))) / 100) * (applyfrom.getLevel() / 30)));
  660.                     if (affected.getHp() < affected.getMaxHp() - affected.getMaxHp() / 20) {
  661.                         applyfrom.gainExp(expadd, true, false, false);
  662.                     }
  663.                 }
  664.                 if (affected != applyfrom && (isGmBuff() || applyfrom.getParty().equals(affected.getParty()))) {
  665.                     boolean isRessurection = isResurrection();
  666.                     if ((isRessurection && !affected.isAlive()) || (!isRessurection && affected.isAlive())) {
  667.                         affectedp.add(affected);
  668.                     }
  669.                     boolean isTimeLeap = isTimeLeap();
  670.                     if (isTimeLeap) {
  671.                         for (PlayerCoolDownValueHolder i : affected.getAllCooldowns()) {
  672.                             affected.removeCooldown(i.skillId);
  673.                         }
  674.                     }
  675.                 }
  676.             }
  677.             for (MapleCharacter affected : affectedp) {
  678.                 // TODO actually heal (and others) shouldn't recalculate everything
  679.                 // for heal this is an actual bug since heal hp is decreased with the number
  680.                 // of affected players
  681.                 applyTo(applyfrom, affected, false, null);
  682.                 affected.getClient().getSession().write(MaplePacketCreator.showOwnBuffEffect(sourceid, 2));
  683.                 affected.getMap().broadcastMessage(affected, MaplePacketCreator.showBuffeffect(affected.getId(), sourceid, 2, (byte) 3), false);
  684.             }
  685.         }
  686.     }
  687.     private void applyMonsterBuff(MapleCharacter applyfrom) {
  688.         Rectangle bounds = calculateBoundingBox(applyfrom.getPosition(), applyfrom.isFacingLeft());
  689.         List<MapleMapObject> affected = applyfrom.getMap().getMapObjectsInRect(bounds, Arrays.asList(MapleMapObjectType.MONSTER));
  690.         ISkill skill_ = SkillFactory.getSkill(sourceid);
  691.         int i = 0;
  692.         for (MapleMapObject mo : affected) {
  693.             MapleMonster monster = (MapleMonster) mo;
  694.             if (makeChanceResult()) {
  695.                 monster.applyStatus(applyfrom, new MonsterStatusEffect(getMonsterStati(), skill_, false), isPoison(), getDuration());
  696.             }
  697.             i++;
  698.             if (i >= mobCount) {
  699.                 break;
  700.             }
  701.         }
  702.     }
  703.     private Rectangle calculateBoundingBox(Point posFrom, boolean facingLeft) {
  704.         Point mylt;
  705.         Point myrb;
  706.         if (facingLeft) {
  707.             mylt = new Point(lt.x + posFrom.x, lt.y + posFrom.y);
  708.             myrb = new Point(rb.x + posFrom.x, rb.y + posFrom.y);
  709.         } else {
  710.             myrb = new Point(lt.x * -1 + posFrom.x, rb.y + posFrom.y);
  711.             mylt = new Point(rb.x * -1 + posFrom.x, lt.y + posFrom.y);
  712.         }
  713.         Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
  714.         return bounds;
  715.     }
  716.     public void silentApplyBuff(MapleCharacter chr, long starttime) {
  717.         int localDuration = duration;
  718.         localDuration = alchemistModifyVal(chr, localDuration, false);
  719.         CancelEffectAction cancelAction = new CancelEffectAction(chr, this, starttime);
  720.         ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - System.currentTimeMillis()));
  721.         chr.registerEffect(this, starttime, schedule);
  722.         SummonMovementType summonMovementType = getSummonMovementType();
  723.         if (summonMovementType != null) {
  724.             final MapleSummon tosummon = new MapleSummon(chr, sourceid, chr.getPosition(), summonMovementType);
  725.             if (!tosummon.isPuppet()) {
  726.                 chr.getMap().spawnSummon(tosummon);
  727.                 chr.getCheatTracker().resetSummonAttack();
  728.                 chr.getSummons().put(sourceid, tosummon);
  729.                 tosummon.addHP(x);
  730.             }
  731.         }
  732.     }
  733.     private void applyBuffEffect(MapleCharacter applyfrom, MapleCharacter applyto, boolean primary) {
  734.         if (sourceid != 5221006) {
  735.             if (!this.isMonsterRiding()) {
  736.                 applyto.cancelEffect(this, true, -1);
  737.             }
  738.         } else {
  739.             applyto.cancelEffect(this, true, -1);
  740.         }
  741.         List<Pair<MapleBuffStat, Integer>> localstatups = statups;
  742.         int localDuration = duration;
  743.         int localsourceid = sourceid;
  744.         int localX = x;
  745.         int localY = y;
  746.         int seconds = localDuration / 1000;
  747.         MapleMount givemount = null;
  748.         if (isMonsterRiding()) {
  749.             int ridingLevel = 0; // mount id
  750.             IItem mount = applyfrom.getInventory(MapleInventoryType.EQUIPPED).getItem((byte) -18);
  751.             if (mount != null) {
  752.                 ridingLevel = mount.getItemId();
  753.             }
  754.             if (sourceid == 5221006) {
  755.                 ridingLevel = 1932000;
  756.                 givemount = new MapleMount(applyto, ridingLevel, 5221006);
  757.                 givemount.setActive(false);
  758.             } else {
  759.                 if (applyto.getMount() == null) {
  760.                     applyto.Mount(ridingLevel, sourceid);
  761.                 }
  762.                 givemount = applyto.getMount();
  763.                 givemount.startSchedule();
  764.                 givemount.setActive(true);
  765.             }
  766.             localDuration = sourceid;
  767.             localsourceid = ridingLevel;
  768.             localstatups = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MONSTER_RIDING, 0));
  769.         }
  770.         if (isPirateMorph()) {
  771.             localstatups = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MORPH, getMorph(applyto)));
  772.         }
  773.         if (primary) {
  774.             localDuration = alchemistModifyVal(applyfrom, localDuration, false);
  775.         }
  776. if (localstatups.size() > 0) {
  777.             if (isDash()) {
  778.                 localstatups = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DASH, 1));
  779.                 applyto.getClient().getSession().write(MaplePacketCreator.giveDash(localstatups, localX, localY, seconds));
  780.             } else {
  781.                 applyto.getClient().getSession().write(MaplePacketCreator.giveBuff((skill ? localsourceid : -localsourceid), localDuration, localstatups));
  782.             }
  783.         } else {
  784.             //log.warn(MapleClient.getLogMessage(applyto, "Applying empty statups (skill {}, id {})", skill, sourceid));
  785.         }
  786.         if (isMonsterRiding()) {
  787.             if (givemount.getItemId() != 0) {
  788.                 applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.showMonsterRiding(applyto.getId(), Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MONSTER_RIDING, 1)), givemount), false);
  789.             }
  790.             localDuration = duration;
  791.         }
  792.         if (isDs()) {
  793.             List<Pair<MapleBuffStat, Integer>> dsstat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DARKSIGHT, 0));
  794.             applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat, this), false);
  795.         }
  796.         if (isCombo()) {
  797.             List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.COMBO, 1));
  798.             applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.giveForeignBuff(applyto.getId(), stat, this), false);
  799.         }
  800.         if (isShadowPartner()) {
  801.             List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SHADOWPARTNER, 0));
  802.             applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.giveForeignBuff(applyto.getId(), stat, this), false);
  803.         }
  804.         if (isSoulArrow()) {
  805.             List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.SOULARROW, 0));
  806.             applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.giveForeignBuff(applyto.getId(), stat, this), false);
  807.         }
  808.         if (isEnrage()) {
  809.             applyto.handleOrbconsume();
  810.         }
  811.         if (isMorph()) {
  812.             List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.MORPH, Integer.valueOf(getMorph(applyto))));
  813.             applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.giveForeignBuff(applyto.getId(), stat, this), false);
  814.         }
  815.         if (isTimeLeap()) {
  816.             for (PlayerCoolDownValueHolder i : applyto.getAllCooldowns()) {
  817.                 if (i.skillId != 5121010) {
  818.                     applyto.removeCooldown(i.skillId);
  819.                 }
  820.             }
  821.         }
  822.         if (localstatups.size() > 0) {
  823.             long starttime = System.currentTimeMillis();
  824.             CancelEffectAction cancelAction = new CancelEffectAction(applyto, this, starttime);
  825.             ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, localDuration);
  826.             applyto.registerEffect(this, starttime, schedule);
  827.         }
  828.         if (primary) {
  829.             if (isDash()) {
  830.                 applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.showDashEffecttoOthers(applyto.getId(), localX, localY, seconds), false);
  831.             } else if (isInfusion()) {
  832.                 applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.giveForeignInfusion(applyto.getId(), x, seconds), false);
  833.             } else {
  834.                 applyto.getMap().broadcastMessage(applyto, MaplePacketCreator.showBuffeffect(applyto.getId(), sourceid, 1, (byte) 3), false);
  835.             }
  836.         }
  837.     }
  838.     private int calcHPChange(MapleCharacter applyfrom, boolean primary) {
  839.         int hpchange = 0;
  840.         if (hp != 0) {
  841.             if (!skill) {
  842.                 if (primary) {
  843.                     hpchange += alchemistModifyVal(applyfrom, hp, true);
  844.                 } else {
  845.                     hpchange += hp;
  846.                 }
  847.             } else { // assumption: this is heal
  848.                 hpchange += makeHealHP(hp / 100.0, applyfrom.getTotalMagic(), 3, 5);
  849.             }
  850.         }
  851.         if (hpR != 0) {
  852.             hpchange += (int) (applyfrom.getCurrentMaxHp() * hpR);
  853.         }
  854.         // actually receivers probably never get any hp when it's not heal but whatever
  855.         if (primary) {
  856.             if (hpCon != 0) {
  857.                 hpchange -= hpCon;
  858.             }
  859.         }
  860.         if (isChakra()) {
  861.             hpchange += makeHealHP(getY() / 100.0, applyfrom.getTotalLuk(), 2.3, 3.5);
  862.         }
  863.         return hpchange;
  864.     }
  865.     private int makeHealHP(double rate, double stat, double lowerfactor, double upperfactor) {
  866.         int maxHeal = (int) (stat * upperfactor * rate);
  867.         int minHeal = (int) (stat * lowerfactor * rate);
  868.         return (int) ((Math.random() * (maxHeal - minHeal + 1)) + minHeal);
  869.     }
  870.     private int calcMPChange(MapleCharacter applyfrom, boolean primary) {
  871.         int mpchange = 0;
  872.         if (mp != 0) {
  873.             if (primary) {
  874.                 mpchange += alchemistModifyVal(applyfrom, mp, true);
  875.             } else {
  876.                 mpchange += mp;
  877.             }
  878.         }
  879.         if (mpR != 0) {
  880.             mpchange += (int) (applyfrom.getCurrentMaxMp() * mpR);
  881.         }
  882.         if (primary) {
  883.             if (mpCon != 0) {
  884.                 double mod = 1.0;
  885.                 boolean isAFpMage = applyfrom.getJob().isA(MapleJob.FP_MAGE);
  886.                 if (isAFpMage || applyfrom.getJob().isA(MapleJob.IL_MAGE)) {
  887.                     ISkill amp;
  888.                     if (isAFpMage) {
  889.                         amp = SkillFactory.getSkill(2110001);
  890.                     } else {
  891.                         amp = SkillFactory.getSkill(2210001);
  892.                     }
  893.                     int ampLevel = applyfrom.getSkillLevel(amp);
  894.                     if (ampLevel > 0) {
  895.                         MapleStatEffect ampStat = amp.getEffect(ampLevel);
  896.                         mod = ampStat.getX() / 100.0;
  897.                     }
  898.                 }
  899.                 mpchange -= mpCon * mod;
  900.                 if (applyfrom.getBuffedValue(MapleBuffStat.INFINITY) != null) {
  901.                     mpchange = 0;
  902.                 }
  903.             }
  904.         }
  905.         return mpchange;
  906.     }
  907.     private int alchemistModifyVal(MapleCharacter chr, int val, boolean withX) {
  908.         if (!skill && chr.getJob().isA(MapleJob.HERMIT)) {
  909.             MapleStatEffect alchemistEffect = getAlchemistEffect(chr);
  910.             if (alchemistEffect != null) {
  911.                 return (int) (val * ((withX ? alchemistEffect.getX() : alchemistEffect.getY()) / 100.0));
  912.             }
  913.         }
  914.         return val;
  915.     }
  916.     private MapleStatEffect getAlchemistEffect(MapleCharacter chr) {
  917.         ISkill alchemist = SkillFactory.getSkill(4110000);
  918.         int alchemistLevel = chr.getSkillLevel(alchemist);
  919.         if (alchemistLevel == 0) {
  920.             return null;
  921.         }
  922.         return alchemist.getEffect(alchemistLevel);
  923.     }
  924.     public void setSourceId(int newid) {
  925.         sourceid = newid;
  926.     }
  927.     private boolean isGmBuff() {
  928.         switch (sourceid) {
  929.             case 1005: // echo of hero acts like a gm buff
  930.             case 9101000:
  931.             case 9101001:
  932.             case 9101002:
  933.             case 9101003:
  934.             case 9101005:
  935.             case 9101008:
  936.                 return true;
  937.             default:
  938.                 return false;
  939.         }
  940.     }
  941.     private boolean isMonsterBuff() {
  942.         if (!skill) {
  943.             return false;
  944.         }
  945.         switch (sourceid) {
  946.             case 1201006: // threaten
  947.             case 2101003: // fp slow
  948.             case 2201003: // il slow
  949.             case 2211004: // il seal
  950.             case 2111004: // fp seal
  951.             case 2311005: // doom
  952.             case 4111003: // shadow web
  953.                 return true;
  954.         }
  955.         return false;
  956.     }
  957.     private boolean isPartyBuff() {
  958.         if (lt == null || rb == null) {
  959.             return false;
  960.         }
  961.         if ((sourceid >= 1211003 && sourceid <= 1211008) || sourceid == 1221003 || sourceid == 1221004) { // wk charges have lt and rb set but are neither player nor monster buffs
  962.             return false;
  963.         }
  964.         return true;
  965.     }
  966.     public boolean isHeal() {
  967.         return sourceid == 2301002 || sourceid == 9101000;
  968.     }
  969.     public boolean isResurrection() {
  970.         return sourceid == 9101005 || sourceid == 2321006;
  971.     }
  972.     public boolean isTimeLeap() {
  973.         return sourceid == 5121010;
  974.     }
  975.     public short getHp() {
  976.         return hp;
  977.     }
  978.     public short getMp() {
  979.         return mp;
  980.     }
  981.     public short getWatk() {
  982.         return watk;
  983.     }
  984.     public short getMatk() {
  985.         return matk;
  986.     }
  987.     public short getWdef() {
  988.         return wdef;
  989.     }
  990.     public short getMdef() {
  991.         return mdef;
  992.     }
  993.     public short getAcc() {
  994.         return acc;
  995.     }
  996.     public short getAvoid() {
  997.         return avoid;
  998.     }
  999.     public short getHands() {
  1000.         return hands;
  1001.     }
  1002.     public short getSpeed() {
  1003.         return speed;
  1004.     }
  1005.     public short getJump() {
  1006.         return jump;
  1007.     }
  1008.     public int getDuration() {
  1009.         return duration;
  1010.     }
  1011.     public boolean isOverTime() {
  1012.         return overTime;
  1013.     }
  1014.     public List<Pair<MapleBuffStat, Integer>> getStatups() {
  1015.         return statups;
  1016.     }
  1017.     public boolean sameSource(MapleStatEffect effect) {
  1018.         return this.sourceid == effect.sourceid && this.skill == effect.skill;
  1019.     }
  1020.     public int getX() {
  1021.         return x;
  1022.     }
  1023.     public int getY() {
  1024.         return y;
  1025.     }
  1026.     public int getZ() {
  1027.         return z;
  1028.     }
  1029.     public int getDamage() {
  1030.         return damage;
  1031.     }
  1032.     public int getAttackCount() {
  1033.         return attackCount;
  1034.     }
  1035.     public int getBulletCount() {
  1036.         return bulletCount;
  1037.     }
  1038.     public int getBulletConsume() {
  1039.         return bulletConsume;
  1040.     }
  1041.     public int getMoneyCon() {
  1042.         return moneyCon;
  1043.     }
  1044.     public int getCooldown() {
  1045.         return cooldown;
  1046.     }
  1047.     public Map<MonsterStatus, Integer> getMonsterStati() {
  1048.         return monsterStatus;
  1049.     }
  1050.     public boolean isHide() {
  1051.         return skill && sourceid == 9101004;
  1052.     }
  1053.     public boolean isDragonBlood() {
  1054.         return skill && sourceid == 1311008;
  1055.     }
  1056.     public boolean isBerserk() {
  1057.         return skill && sourceid == 1320006;
  1058.     }
  1059.     private boolean isDs() {
  1060.         return skill && sourceid == 4001003;
  1061.     }
  1062.     private boolean isCombo() {
  1063.         return skill && sourceid == 1111002;
  1064.     }
  1065.     private boolean isEnrage() {
  1066.         return skill && sourceid == 1121010;
  1067.     }
  1068.     public boolean isBeholder() {
  1069.         return skill && sourceid == 1321007;
  1070.     }
  1071.     private boolean isShadowPartner() {
  1072.         return skill && sourceid == 4111002;
  1073.     }
  1074.     private boolean isChakra() {
  1075.         return skill && sourceid == 4211001;
  1076.     }
  1077.     public boolean isMonsterRiding() {
  1078.         return skill && (sourceid == 1004 || sourceid == 5221006);
  1079.     }
  1080.     public boolean isMagicDoor() {
  1081.         return skill && sourceid == 2311002;
  1082.     }
  1083.     public boolean isMesoGuard() {
  1084.         return skill && sourceid == 4211005;
  1085.     }
  1086.     public boolean isCharge() {
  1087.         return skill && sourceid >= 1211003 && sourceid <= 1211008;
  1088.     }
  1089.     public boolean isPoison() {
  1090.         return skill && (sourceid == 2111003 || sourceid == 2101005 || sourceid == 2111006);
  1091.     }
  1092.     private boolean isMist() {
  1093.         return skill && (sourceid == 2111003 || sourceid == 4221006); // poison mist and smokescreen
  1094.     }
  1095.     private boolean isSoulArrow() {
  1096.         return skill && (sourceid == 3101004 || sourceid == 3201004); // bow and crossbow
  1097.     }
  1098.     private boolean isShadowClaw() {
  1099.         return skill && sourceid == 4121006;
  1100.     }
  1101.     private boolean isDispel() {
  1102.         return skill && (sourceid == 2311001 || sourceid == 9101000);
  1103.     }
  1104.     private boolean isHeroWill() {
  1105.         return skill && (sourceid == 1121011 || sourceid == 1221012 || sourceid == 1321010 || sourceid == 2121008 || sourceid == 2221008 || sourceid == 2321009 || sourceid == 3121009 || sourceid == 3221008 || sourceid == 4121009 || sourceid == 4221008 || sourceid == 5121008 || sourceid == 5221010);
  1106.     }
  1107.     private boolean isDash() {
  1108.         return skill && sourceid == 5001005;
  1109.     }
  1110.     public boolean isPirateMorph() {
  1111.         return skill && (sourceid == 5111005 || sourceid == 5121003);
  1112.     }
  1113.     public boolean isInfusion() {
  1114.         return skill && sourceid == 5121009;
  1115.     }
  1116.     public boolean isMorph() {
  1117.         return morphId > 0;
  1118.     }
  1119.     public int getMorph() {
  1120.         return morphId;
  1121.     }
  1122.     public int getMorph(MapleCharacter chr) {
  1123.         if (morphId == 1000) {// check for gender on pirate morph
  1124.             return 1000 + chr.getGender();
  1125.         } else if (morphId == 1100) {
  1126.             return 1100 + chr.getGender();
  1127.         }
  1128.         return morphId;
  1129.     }
  1130.     public SummonMovementType getSummonMovementType() {
  1131.         if (!skill) {
  1132.             return null;
  1133.         }
  1134.         switch (sourceid) {
  1135.             case 3211002: // puppet sniper
  1136.             case 3111002: // puppet ranger
  1137.             case 5211001: // octopus - pirate
  1138.             case 5220002: // advanced octopus - pirate
  1139.                 return SummonMovementType.STATIONARY;
  1140.             case 3211005: // golden eagle
  1141.             case 3111005: // golden hawk
  1142.             case 2311006: // summon dragon
  1143.             case 3221005: // frostprey
  1144.             case 3121006: // phoenix
  1145.             case 5211002: // bird - pirate
  1146.                 return SummonMovementType.CIRCLE_FOLLOW;
  1147.             case 1321007: // beholder
  1148.             case 2121005: // elquines
  1149.             case 2221005: // ifrit
  1150.             case 2321003: // bahamut
  1151.                 return SummonMovementType.FOLLOW;
  1152.         }
  1153.         return null;
  1154.     }
  1155.     public boolean isSkill() {
  1156.         return skill;
  1157.     }
  1158.     public int getSourceId() {
  1159.         return sourceid;
  1160.     }
  1161.     /**
  1162.      *
  1163.      * @return true if the effect should happen based on it's probablity, false otherwise
  1164.      */
  1165.     public boolean makeChanceResult() {
  1166.         return prop == 1.0 || Math.random() < prop;
  1167.     }
  1168.     public static class CancelEffectAction implements Runnable {
  1169.         private MapleStatEffect effect;
  1170.         private WeakReference<MapleCharacter> target;
  1171.         private long startTime;
  1172.         public CancelEffectAction(MapleCharacter target, MapleStatEffect effect, long startTime) {
  1173.             this.effect = effect;
  1174.             this.target = new WeakReference<MapleCharacter>(target);
  1175.             this.startTime = startTime;
  1176.         }
  1177.         @Override
  1178.         public void run() {
  1179.             MapleCharacter realTarget = target.get();
  1180.             if (realTarget != null) {
  1181.                 realTarget.cancelEffect(effect, false, startTime);
  1182.             }
  1183.         }
  1184.     }
  1185.     public int getMastery() {
  1186.         return mastery;
  1187.     }
  1188.     public int getRange() {
  1189.         return range;
  1190.     }
  1191.     public double getProp() {
  1192.         return iProp;
  1193.     }
  1194. }