/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * http://www.gnu.org/copyleft/gpl.html */ package l1j.server.server.model; import static l1j.server.server.model.skill.L1SkillId.ABSOLUTE_BARRIER; import static l1j.server.server.model.skill.L1SkillId.BERSERKERS; import static l1j.server.server.model.skill.L1SkillId.BONE_BREAK; import static l1j.server.server.model.skill.L1SkillId.BOUNCE_ATTACK; import static l1j.server.server.model.skill.L1SkillId.BURNING_SLASH; import static l1j.server.server.model.skill.L1SkillId.BURNING_SPIRIT; import static l1j.server.server.model.skill.L1SkillId.BURNING_WEAPON; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_0_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_1_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_2_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_3_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_4_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_5_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_6_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_1_7_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_0_N; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_0_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_1_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_2_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_3_N; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_3_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_4_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_5_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_6_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_2_7_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_0_N; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_0_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_1_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_2_N; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_2_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_3_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_4_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_5_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_6_S; import static l1j.server.server.model.skill.L1SkillId.COOKING_3_7_S; import static l1j.server.server.model.skill.L1SkillId.DOUBLE_BRAKE; import static l1j.server.server.model.skill.L1SkillId.DRAGON_SKIN; import static l1j.server.server.model.skill.L1SkillId.EARTH_BIND; import static l1j.server.server.model.skill.L1SkillId.ELEMENTAL_FIRE; import static l1j.server.server.model.skill.L1SkillId.ENCHANT_VENOM; import static l1j.server.server.model.skill.L1SkillId.FIRE_BLESS; import static l1j.server.server.model.skill.L1SkillId.FIRE_WEAPON; import static l1j.server.server.model.skill.L1SkillId.FREEZING_BLIZZARD; import static l1j.server.server.model.skill.L1SkillId.FREEZING_BREATH; import static l1j.server.server.model.skill.L1SkillId.ICE_LANCE; import static l1j.server.server.model.skill.L1SkillId.IMMUNE_TO_HARM; import static l1j.server.server.model.skill.L1SkillId.MIRROR_IMAGE; import static l1j.server.server.model.skill.L1SkillId.PATIENCE; import static l1j.server.server.model.skill.L1SkillId.REDUCTION_ARMOR; import static l1j.server.server.model.skill.L1SkillId.RESIST_FEAR; import static l1j.server.server.model.skill.L1SkillId.SOUL_OF_FLAME; import static l1j.server.server.model.skill.L1SkillId.STATUS_CURSE_BARLOG; import static l1j.server.server.model.skill.L1SkillId.STATUS_CURSE_YAHEE; import static l1j.server.server.model.skill.L1SkillId.STATUS_HOLY_MITHRIL_POWDER; import static l1j.server.server.model.skill.L1SkillId.STATUS_HOLY_WATER; import static l1j.server.server.model.skill.L1SkillId.STATUS_HOLY_WATER_OF_EVA; import static l1j.server.server.model.skill.L1SkillId.STATUS_WEAKNESS_EXPOSURE_LV1; import static l1j.server.server.model.skill.L1SkillId.STATUS_WEAKNESS_EXPOSURE_LV2; import static l1j.server.server.model.skill.L1SkillId.STATUS_WEAKNESS_EXPOSURE_LV3; import static l1j.server.server.model.skill.L1SkillId.UNCANNY_DODGE; import java.util.Random; import java.util.logging.Logger; import l1j.server.Config; import l1j.server.server.ActionCodes; import l1j.server.server.WarTimeController; import l1j.server.server.datatables.SkillsTable; import l1j.server.server.model.Instance.L1DollInstance; import l1j.server.server.model.Instance.L1ItemInstance; import l1j.server.server.model.Instance.L1NpcInstance; import l1j.server.server.model.Instance.L1PcInstance; import l1j.server.server.model.Instance.L1PetInstance; import l1j.server.server.model.Instance.L1SummonInstance; import l1j.server.server.model.gametime.L1GameTimeClock; import l1j.server.server.model.poison.L1DamagePoison; import l1j.server.server.model.poison.L1ParalysisPoison; import l1j.server.server.model.poison.L1SilencePoison; import l1j.server.server.model.skill.L1SkillId; import l1j.server.server.serverpackets.S_AttackMissPacket; import l1j.server.server.serverpackets.S_AttackPacket; import l1j.server.server.serverpackets.S_AttackPacketForNpc; import l1j.server.server.serverpackets.S_DoActionGFX; import l1j.server.server.serverpackets.S_EffectLocation; import l1j.server.server.serverpackets.S_Paralysis; import l1j.server.server.serverpackets.S_ServerMessage; import l1j.server.server.serverpackets.S_SkillIconGFX; import l1j.server.server.serverpackets.S_SkillSound; import l1j.server.server.serverpackets.S_UseArrowSkill; import l1j.server.server.serverpackets.S_UseAttackSkill; import l1j.server.server.templates.L1Skills; import l1j.server.server.types.Point; import war.W_Method; import war.mod.W_DoMod; public class L1Attack { private static Logger _log = Logger.getLogger(L1Attack.class.getName()); private L1PcInstance _pc = null; private L1Character _target = null; private L1PcInstance _targetPc = null; private L1NpcInstance _npc = null; private L1NpcInstance _targetNpc = null; private final int _targetId; private int _targetX; private int _targetY; private int _statusDamage = 0; private static final Random _random = new Random(); private int _hitRate = 0; private int _calcType; private static final int PC_PC = 1; private static final int PC_NPC = 2; private static final int NPC_PC = 3; private static final int NPC_NPC = 4; private boolean _isHit = false; private int _damage = 0; private int _drainMana = 0; private int _drainHp = 0; private int _attckGrfxId = 0; private int _attckActId = 0; // 攻撃者がプレイヤーの場合の武器情報 private L1ItemInstance weapon = null; private int _weaponId = 0; private int _weaponType = 0; private int _weaponType2 = 0; private int _weaponAddHit = 0; private int _weaponAddDmg = 0; private int _weaponSmall = 0; private int _weaponLarge = 0; private int _weaponRange = 1; private int _weaponBless = 1; private int _weaponEnchant = 0; private int _weaponMaterial = 0; private int _weaponDoubleDmgChance = 0; private int _weaponWeaknessExposureChance = 0; private int _weaponAttrEnchantKind = 0; private int _weaponAttrEnchantLevel = 0; private L1ItemInstance _arrow = null; private L1ItemInstance _sting = null; private int _leverage = 10; // 1/10倍で表現する。 private int _skillId; private double _skillDamage = 0; public void setLeverage(int i) { _leverage = i; } private int getLeverage() { return _leverage; } // 攻撃者がプレイヤーの場合のステータスによる補正 // private static final int[] strHit = { -2, -2, -2, -2, -2, -2, -2, -2, -2, // -2, -1, -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, // 9, 10, 10, 11, 11, 12, 12, 13, 13, 14 }; // private static final int[] dexHit = { -2, -2, -2, -2, -2, -2, -2, -2, -2, // -1, -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, // 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14 }; /* * private static final int[] strHit = { -2, -2, -2, -2, -2, -2, -2, // * 0〜7まで -1, -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, // * 8〜26まで 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, // * 27〜44まで 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17}; // * 45〜59まで * * private static final int[] dexHit = { -2, -2, -2, -2, -2, -2, -1, -1, 0, * 0, // 1〜10まで 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, * 15, 16, // 11〜30まで 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, * 30, 31, // 31〜45まで 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, * 45, 46 }; // 46〜60まで * * private static final int[] strDmg = new int[128]; * * static { // STRダメージ補正 int dmg = -6; for (int str = 0; str <= 22; str++) { * // 0〜22は2毎に+1 if (str % 2 == 1) { dmg++; } strDmg[str] = dmg; } for (int * str = 23; str <= 28; str++) { // 23〜28は3毎に+1 if (str % 3 == 2) { dmg++; } * strDmg[str] = dmg; } for (int str = 29; str <= 32; str++) { // * 29〜32は2毎に+1 if (str % 2 == 1) { dmg++; } strDmg[str] = dmg; } for (int * str = 33; str <= 39; str++) { // 33〜39は1毎に+1 dmg++; strDmg[str] = dmg; } * for (int str = 40; str <= 46; str++) { // 40〜46は1毎に+2 dmg += 2; * strDmg[str] = dmg; } for (int str = 47; str <= 127; str++) { // * 47〜127は1毎に+1 dmg++; strDmg[str] = dmg; } } * * private static final int[] dexDmg = new int[128]; * * static { // DEXダメージ補正 for (int dex = 0; dex <= 14; dex++) { // 0〜14は0 * dexDmg[dex] = 0; } dexDmg[15] = 1; dexDmg[16] = 2; dexDmg[17] = 3; * dexDmg[18] = 4; dexDmg[19] = 4; dexDmg[20] = 4; dexDmg[21] = 5; * dexDmg[22] = 5; dexDmg[23] = 5; int dmg = 5; for (int dex = 24; dex <= * 127; dex++) { // 24〜127は1毎に+1 dmg++; dexDmg[dex] = dmg; } } */ private static final int[] strHit = { -2, -2, -2, -2, -2, -2, -2, // 1〜7 -2, -1, -1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, // 8〜26 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, // 27〜44 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17 }; // 45〜59 private static final int[] dexHit = { -2, -2, -2, -2, -2, -2, -1, -1, 0, 0, // 1〜10 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, // 11〜30 17, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, // 31〜45 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28 }; // 46〜60 private static final int[] strDmg = new int[128]; static { // STRダメージ補正 int dmg = -6; for (int str = 0; str <= 22; str++) { // 0〜22は2毎に+1 if (str % 2 == 1) { dmg++; } strDmg[str] = dmg; } for (int str = 23; str <= 28; str++) { // 23〜28は3毎に+1 if (str % 3 == 2) { dmg++; } strDmg[str] = dmg; } for (int str = 29; str <= 32; str++) { // 29〜32は2毎に+1 if (str % 2 == 1) { dmg++; } strDmg[str] = dmg; } for (int str = 33; str <= 34; str++) { // 33〜34は1毎に+1 dmg++; strDmg[str] = dmg; } for (int str = 35; str <= 127; str++) { // 35〜127は4毎に+1 if (str % 4 == 1) { dmg++; } strDmg[str] = dmg; } } private static final int[] dexDmg = new int[128]; static { // DEXダメージ補正 for (int dex = 0; dex <= 14; dex++) { // 0〜14は0 dexDmg[dex] = 0; } dexDmg[15] = 1; dexDmg[16] = 2; dexDmg[17] = 3; dexDmg[18] = 4; dexDmg[19] = 4; dexDmg[20] = 4; dexDmg[21] = 5; dexDmg[22] = 5; dexDmg[23] = 5; int dmg = 5; for (int dex = 24; dex <= 35; dex++) { // 24〜35は3毎に+1 if (dex % 3 == 1) { dmg++; } dexDmg[dex] = dmg; } for (int dex = 36; dex <= 127; dex++) { // 36〜127は4毎に1 if (dex % 4 == 1) { dmg++; } dexDmg[dex] = dmg; } } public void setActId(int actId) { _attckActId = actId; } public void setGfxId(int gfxId) { _attckGrfxId = gfxId; } public int getActId() { return _attckActId; } public int getGfxId() { return _attckGrfxId; } public L1Attack(L1Character attacker, L1Character target) { this(attacker, target, 0); } public L1Attack(L1Character attacker, L1Character target, int skillId) { _skillId = skillId; if (_skillId != 0) { L1Skills skills = SkillsTable.getInstance().getTemplate(_skillId); _skillDamage = skills.getDamageValue(); } else { _skillDamage = 0; } if (attacker instanceof L1PcInstance) { _pc = (L1PcInstance) attacker; if (target instanceof L1PcInstance) { _targetPc = (L1PcInstance) target; _calcType = PC_PC; } else if (target instanceof L1NpcInstance) { _targetNpc = (L1NpcInstance) target; _calcType = PC_NPC; } // 武器情報の取得 weapon = _pc.getWeapon(); if (weapon != null) { _weaponId = weapon.getItem().getItemId(); _weaponType = weapon.getItem().getType1(); _weaponType2 = weapon.getItem().getType(); _weaponAddHit = weapon.getItem().getHitModifier() + weapon.getHitByMagic(); _weaponAddDmg = weapon.getItem().getDmgModifier() + weapon.getDmgByMagic() + W_Method.modValue(weapon, 1); _weaponSmall = weapon.getItem().getDmgSmall(); _weaponLarge = weapon.getItem().getDmgLarge() + W_Method.modValue(weapon, 2); _weaponRange = weapon.getItem().getRange(); _weaponBless = weapon.getItem().getBless(); if (_weaponType != 20 && _weaponType != 62) { _weaponEnchant = weapon.getEnchantLevel() - weapon.get_durability(); // 損傷分マイナス } else { _weaponEnchant = weapon.getEnchantLevel(); } _weaponMaterial = weapon.getItem().getMaterial(); if (_weaponType == 20) { // アローの取得 _arrow = _pc.getInventory().getArrow(); if (_arrow != null) { _weaponBless = _arrow.getItem().getBless(); _weaponMaterial = _arrow.getItem().getMaterial(); } } if (_weaponType == 62) { // スティングの取得 _sting = _pc.getInventory().getSting(); if (_sting != null) { _weaponBless = _sting.getItem().getBless(); _weaponMaterial = _sting.getItem().getMaterial(); } } _weaponDoubleDmgChance = weapon.getItem().getDoubleDmgChance() + W_Method.modValue(weapon, 6) + W_Method.modValue(weapon, 7); _weaponWeaknessExposureChance = weapon.getItem().getWeaknessExposure() + W_Method.modValue(weapon, 31); _weaponAttrEnchantKind = weapon.getAttrEnchantKind(); _weaponAttrEnchantLevel = weapon.getAttrEnchantLevel(); } // ステータスによる追加ダメージ補正 if (_weaponType == 20) { // 弓の場合はDEX値参照 // _statusDamage = dexDmg[_pc.getDex()]; } else { // それ以外はSTR値参照 // _statusDamage = strDmg[_pc.getStr()]; } _statusDamage = 0; } else if (attacker instanceof L1NpcInstance) { _npc = (L1NpcInstance) attacker; if (target instanceof L1PcInstance) { _targetPc = (L1PcInstance) target; _calcType = NPC_PC; } else if (target instanceof L1NpcInstance) { _targetNpc = (L1NpcInstance) target; _calcType = NPC_NPC; } } _target = target; _targetId = target.getId(); _targetX = target.getX(); _targetY = target.getY(); } /* ■■■■■■■■■■■■■■■■ 命中判定 ■■■■■■■■■■■■■■■■ */ public boolean calcHit() { if (_calcType == PC_PC || _calcType == PC_NPC) { if (_weaponRange != -1) { if (_pc.getLocation().getTileLineDistance(_target.getLocation()) > _weaponRange + 1) { // BIGのモンスターに対応するため射程範囲 // + // 1 _isHit = false; // 射程範囲外 return _isHit; } } else { if (!_pc.getLocation().isInScreen(_target.getLocation())) { _isHit = false; // 射程範囲外 return _isHit; } } /* * if (_weaponType == 20 && _weaponId != 190 && _arrow == null) { // * _isHit = false; // 矢がない場合はミス _isHit = true; } else if * (_weaponType == 62 && _sting == null) { // _isHit = false; // * スティングがない場合はミス _isHit = true; } else */if (!_pc.glanceCheck(_targetX, _targetY)) { _isHit = false; // 攻撃者がプレイヤーの場合は障害物判定 } else if (_weaponId == 247 || _weaponId == 248 || _weaponId == 249) { _isHit = false; // 試練の剣B〜C 攻撃無効 } else if (_calcType == PC_PC) { _isHit = calcPcPcHit(); } else if (_calcType == PC_NPC) { _isHit = calcPcNpcHit(); } } else if (_calcType == NPC_PC) { _isHit = calcNpcPcHit(); } else if (_calcType == NPC_NPC) { _isHit = calcNpcNpcHit(); } return _isHit; } // ●●●● プレイヤー から プレイヤー への命中判定 ●●●● /* * PCへの命中率 =(PCのLv+クラス補正+STR補正+DEX補正+武器補正+DAIの枚数/2+魔法補正)×0.68−10 * これで算出された数値は自分が最大命中(95%)を与える事のできる相手側PCのAC そこから相手側PCのACが1良くなる毎に自命中率から1引いていく * 最小命中率5% 最大命中率95% */ private boolean calcPcPcHit() { /* * _hitRate = _pc.getLevel(); * * if (_pc.getStr() > 59) { _hitRate += strHit[58]; } else { _hitRate += * strHit[_pc.getStr() - 1]; } * * if (_pc.getDex() > 60) { _hitRate += dexHit[59]; } else { _hitRate += * dexHit[_pc.getDex() - 1]; } * * if (_weaponType != 20 && _weaponType != 62) { _hitRate += * _weaponAddHit + _pc.getHitup() + _pc.getOriginalHitup() + * (_weaponEnchant / 2); } else { _hitRate += _weaponAddHit + * _pc.getBowHitup() + _pc.getOriginalBowHitup() + (_weaponEnchant / 2); * } * * if (_weaponType != 20 && _weaponType != 62) { // 防具による追加命中 _hitRate * += _pc.getHitModifierByArmor(); } else { _hitRate += * _pc.getBowHitModifierByArmor(); } * * if (80 < _pc.getInventory().getWeight240() // 重量による命中補正 && 120 >= * _pc.getInventory().getWeight240()) { _hitRate -= 1; } else if (121 <= * _pc.getInventory().getWeight240() && 160 >= * _pc.getInventory().getWeight240()) { _hitRate -= 3; } else if (161 <= * _pc.getInventory().getWeight240() && 200 >= * _pc.getInventory().getWeight240()) { _hitRate -= 5; } * * if (_pc.hasSkillEffect(COOKING_2_0_N) // 料理による追加命中 || * _pc.hasSkillEffect(COOKING_2_0_S)) { if (_weaponType != 20 && * _weaponType != 62) { _hitRate += 1; } } if * (_pc.hasSkillEffect(COOKING_3_2_N) // 料理による追加命中 || * _pc.hasSkillEffect(COOKING_3_2_S)) { if (_weaponType != 20 && * _weaponType != 62) { _hitRate += 2; } } if * (_pc.hasSkillEffect(COOKING_2_3_N) // 料理による追加命中 || * _pc.hasSkillEffect(COOKING_2_3_S) || * _pc.hasSkillEffect(COOKING_3_0_N) || * _pc.hasSkillEffect(COOKING_3_0_S)) { if (_weaponType == 20 || * _weaponType == 62) { _hitRate += 1; } } * * int attackerDice = _random.nextInt(20) + 1 + _hitRate - 10; * * if (_targetPc.hasSkillEffect(UNCANNY_DODGE)) { attackerDice -= 5; } * * if (_targetPc.hasSkillEffect(MIRROR_IMAGE)) { attackerDice -= 5; } * * if (_targetPc.hasSkillEffect(RESIST_FEAR)) { attackerDice += 5; } * * int defenderDice = 0; * * int defenderValue = (int) (_targetPc.getAc() * 1.5) * -1; * * if (_targetPc.getAc() >= 0) { defenderDice = 10 - _targetPc.getAc(); * } else if (_targetPc.getAc() < 0) { defenderDice = 10 + * _random.nextInt(defenderValue) + 1; } * * int fumble = _hitRate - 9; int critical = _hitRate + 10; * * if (attackerDice <= fumble) { _hitRate = 0; } else if (attackerDice * >= critical) { _hitRate = 100; } else { if (attackerDice > * defenderDice) { _hitRate = 100; } else if (attackerDice <= * defenderDice) { _hitRate = 0; } } * * if (_weaponType2 == 17) { _hitRate = 100; // キーリンクの命中率は100% } * * if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) { _hitRate = 0; } if * (_targetPc.hasSkillEffect(ICE_LANCE)) { _hitRate = 0; } if * (_targetPc.hasSkillEffect(FREEZING_BLIZZARD)) { _hitRate = 0; } if * (_targetPc.hasSkillEffect(FREEZING_BREATH)) { _hitRate = 0; } if * (_targetPc.hasSkillEffect(EARTH_BIND)) { _hitRate = 0; } */ int _hitRate = 90; int rnd = _random.nextInt(100) + 1; if (_weaponType == 20 && _hitRate > rnd) { // 弓の場合、ヒットした場合でもERでの回避を再度行う。 return calcErEvasion(); } return _hitRate >= rnd; } // ●●●● プレイヤー から NPC への命中判定 ●●●● private boolean calcPcNpcHit() { // NPCへの命中率 // =(PCのLv+クラス補正+STR補正+DEX補正+武器補正+DAIの枚数/2+魔法補正)×5−{NPCのAC×(-5)} _hitRate = _pc.getLevel(); if (_pc.getStr() > 59) { _hitRate += strHit[58]; } else { _hitRate += strHit[_pc.getStr() - 1]; } if (_pc.getDex() > 60) { _hitRate += dexHit[59]; } else { _hitRate += dexHit[_pc.getDex() - 1]; } if (_weaponType != 20 && _weaponType != 62) { _hitRate += _weaponAddHit + _pc.getHitup() + _pc.getOriginalHitup() + (_weaponEnchant / 2); } else { _hitRate += _weaponAddHit + _pc.getBowHitup() + _pc.getOriginalBowHitup() + (_weaponEnchant / 2); } if (_weaponType != 20 && _weaponType != 62) { // 防具による追加命中 _hitRate += _pc.getHitModifierByArmor(); } else { _hitRate += _pc.getBowHitModifierByArmor(); } if (80 < _pc.getInventory().getWeight240() // 重量による命中補正 && 120 >= _pc.getInventory().getWeight240()) { _hitRate -= 1; } else if (121 <= _pc.getInventory().getWeight240() && 160 >= _pc.getInventory().getWeight240()) { _hitRate -= 3; } else if (161 <= _pc.getInventory().getWeight240() && 200 >= _pc.getInventory().getWeight240()) { _hitRate -= 5; } if (_pc.hasSkillEffect(COOKING_2_0_N) // 料理による追加命中 || _pc.hasSkillEffect(COOKING_2_0_S)) { if (_weaponType != 20 && _weaponType != 62) { _hitRate += 1; } } if (_pc.hasSkillEffect(COOKING_3_2_N) // 料理による追加命中 || _pc.hasSkillEffect(COOKING_3_2_S)) { if (_weaponType != 20 && _weaponType != 62) { _hitRate += 2; } } if (_pc.hasSkillEffect(COOKING_2_3_N) // 料理による追加命中 || _pc.hasSkillEffect(COOKING_2_3_S) || _pc.hasSkillEffect(COOKING_3_0_N) || _pc.hasSkillEffect(COOKING_3_0_S)) { if (_weaponType == 20 || _weaponType == 62) { _hitRate += 1; } } int attackerDice = _random.nextInt(20) + 1 + _hitRate - 10; if (_targetNpc.hasSkillEffect(UNCANNY_DODGE)) { attackerDice -= 5; } if (_targetNpc.hasSkillEffect(MIRROR_IMAGE)) { attackerDice -= 5; } if (_targetNpc.hasSkillEffect(RESIST_FEAR)) { attackerDice += 5; } int defenderDice = 10 - _targetNpc.getAc(); int fumble = _hitRate - 9; int critical = _hitRate + 10; if (attackerDice <= fumble) { _hitRate = 0; } else if (attackerDice >= critical) { _hitRate = 100; } else { if (attackerDice > defenderDice) { _hitRate = 100; } else if (attackerDice <= defenderDice) { _hitRate = 0; } } if (_weaponType2 == 17) { _hitRate = 100; // キーリンクの命中率は100% } int npcId = _targetNpc.getNpcTemplate().get_npcId(); if (npcId >= 45912 && npcId <= 45915 // 恨みに満ちたソルジャー&ソルジャーゴースト && !_pc.hasSkillEffect(STATUS_HOLY_WATER)) { _hitRate = 0; } if (npcId == 45916 // 恨みに満ちたハメル将軍 && !_pc.hasSkillEffect(STATUS_HOLY_MITHRIL_POWDER)) { _hitRate = 0; } if (npcId == 45941 // 呪われた巫女サエル && !_pc.hasSkillEffect(STATUS_HOLY_WATER_OF_EVA)) { _hitRate = 0; } if (npcId == 45752 // バルログ(変身前) && !_pc.hasSkillEffect(STATUS_CURSE_BARLOG)) { _hitRate = 0; } if (npcId == 45753 // バルログ(変身後) && !_pc.hasSkillEffect(STATUS_CURSE_BARLOG)) { _hitRate = 0; } if (npcId == 45675 // ヤヒ(変身前) && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { _hitRate = 0; } if (npcId == 81082 // ヤヒ(変身後) && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { _hitRate = 0; } if (npcId == 45625 // 混沌 && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { _hitRate = 0; } if (npcId == 45674 // 死 && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { _hitRate = 0; } if (npcId == 45685 // 堕落 && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { _hitRate = 0; } if (npcId >= 46068 && npcId <= 46091 // 欲望の洞窟側mob && _pc.getTempCharGfx() == 6035) { _hitRate = 0; } if (npcId >= 46092 && npcId <= 46106 // 影の神殿側mob && _pc.getTempCharGfx() == 6034) { _hitRate = 0; } int rnd = _random.nextInt(100) + 1; return _hitRate >= rnd; } // ●●●● NPC から プレイヤー への命中判定 ●●●● private boolean calcNpcPcHit() { _hitRate += _npc.getLevel(); if (_npc instanceof L1PetInstance) { // ペットの武器による追加命中 _hitRate += ((L1PetInstance) _npc).getHitByWeapon(); } _hitRate += _npc.getHitup(); int attackerDice = _random.nextInt(20) + 1 + _hitRate - 1; if (_targetPc.hasSkillEffect(UNCANNY_DODGE)) { attackerDice -= 5; } if (_targetPc.hasSkillEffect(MIRROR_IMAGE)) { attackerDice -= 5; } if (_targetPc.hasSkillEffect(RESIST_FEAR)) { attackerDice += 5; } int defenderDice = 0; int defenderValue = (_targetPc.getAc()) * -1; if (_targetPc.getAc() >= 0) { defenderDice = 10 - _targetPc.getAc(); } else if (_targetPc.getAc() < 0) { defenderDice = 10 + _random.nextInt(defenderValue) + 1; } int fumble = _hitRate; int critical = _hitRate + 19; if (attackerDice <= fumble) { _hitRate = 0; } else if (attackerDice >= critical) { _hitRate = 100; } else { if (attackerDice > defenderDice) { _hitRate = 100; } else if (attackerDice <= defenderDice) { _hitRate = 0; } } if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) { _hitRate = 0; } if (_targetPc.hasSkillEffect(ICE_LANCE)) { _hitRate = 0; } if (_targetPc.hasSkillEffect(FREEZING_BLIZZARD)) { _hitRate = 0; } if (_targetPc.hasSkillEffect(FREEZING_BREATH)) { _hitRate = 0; } if (_targetPc.hasSkillEffect(EARTH_BIND)) { _hitRate = 0; } else if (_npc instanceof L1PetInstance) { // 攻撃目標指定、NOPVP if ((_targetPc.getZoneType() == 1) || (_npc.getZoneType() == 1) || (_targetPc.checkNonPvP(_targetPc, _npc))) { _hitRate = 0; } } else if (_npc instanceof L1SummonInstance) { // 攻撃目標指定、NOPVP if ((_targetPc.getZoneType() == 1) || (_npc.getZoneType() == 1) || (_targetPc.checkNonPvP(_targetPc, _npc))) { _hitRate = 0; } } int rnd = _random.nextInt(100) + 1; // NPCの攻撃レンジが10以上の場合で、2以上離れている場合弓攻撃とみなす if (_npc.getNpcTemplate().get_ranged() >= 10 && _hitRate > rnd && _npc.getLocation().getTileLineDistance(new Point(_targetX, _targetY)) >= 2) { return calcErEvasion(); } return _hitRate >= rnd; } // ●●●● NPC から NPC への命中判定 ●●●● private boolean calcNpcNpcHit() { _hitRate += _npc.getLevel(); if (_npc instanceof L1PetInstance) { // ペットの武器による追加命中 _hitRate += ((L1PetInstance) _npc).getHitByWeapon(); } _hitRate += _npc.getHitup(); int attackerDice = _random.nextInt(20) + 1 + _hitRate - 1; if (_targetNpc.hasSkillEffect(UNCANNY_DODGE)) { attackerDice -= 5; } if (_targetNpc.hasSkillEffect(MIRROR_IMAGE)) { attackerDice -= 5; } if (_targetNpc.hasSkillEffect(RESIST_FEAR)) { attackerDice += 5; } int defenderDice = 0; int defenderValue = (_targetNpc.getAc()) * -1; if (_targetNpc.getAc() >= 0) { defenderDice = 10 - _targetNpc.getAc(); } else if (_targetNpc.getAc() < 0) { defenderDice = 10 + _random.nextInt(defenderValue) + 1; } int fumble = _hitRate; int critical = _hitRate + 19; if (attackerDice <= fumble) { _hitRate = 0; } else if (attackerDice >= critical) { _hitRate = 100; } else { if (attackerDice > defenderDice) { _hitRate = 100; } else if (attackerDice <= defenderDice) { _hitRate = 0; } } int rnd = _random.nextInt(100) + 1; return _hitRate >= rnd; } // ●●●● ERによる回避判定 ●●●● private boolean calcErEvasion() { int er = _targetPc.getEr() * 2; int rnd = _random.nextInt(100) + 1; return er < rnd; } /* ■■■■■■■■■■■■■■■ ダメージ算出 ■■■■■■■■■■■■■■■ */ public int calcDamage() { if (_calcType == PC_PC) { _damage = calcPcPcDamage(); } else if (_calcType == PC_NPC) { _damage = calcPcNpcDamage(); } else if (_calcType == NPC_PC) { _damage = calcNpcPcDamage(); } else if (_calcType == NPC_NPC) { _damage = calcNpcNpcDamage(); } return _damage; } // ●●●● プレイヤー から プレイヤー へのダメージ算出 ●●●● public int calcPcPcDamage() { int weaponMaxDamage = _weaponLarge; int weaponDamage = 0; if (_weaponType == 58 && (_random.nextInt(100) + 1) <= _weaponDoubleDmgChance) { // クリティカルヒット weaponDamage = weaponMaxDamage; _pc.sendPackets(new S_SkillSound(_pc.getId(), 3671)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3671)); } else if (_weaponType == 0) {// || _weaponType == 20 || _weaponType == // 62) { // 素手、弓、ガントトレット weaponDamage = 0; } else { // レンジャー if (_pc.getSubClassId() == 5 && _random.nextInt(100) + 1 <= 50 && (_weaponType == 20 || _weaponType == 62)) { weaponMaxDamage *= 1 + _random.nextDouble(); weaponDamage = _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; } else if (_pc.getSubClassId() == 5 && _weaponType != 20 && _weaponType != 62) { weaponMaxDamage *= 1 + _random.nextDouble(); weaponDamage = _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; } else if (_pc.getSubClassId() == 9 && _random.nextInt(100) + 1 <= 20) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 7368)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 7368)); weaponDamage = _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; weaponDamage += _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; } else { weaponDamage = _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; } } if (_pc.hasSkillEffect(SOUL_OF_FLAME) && (_random.nextInt(100) + 1) <= 33) { if (_weaponType != 20 && _weaponType != 62) { weaponDamage = weaponMaxDamage; } } int weaponTotalDamage = weaponDamage + _weaponAddDmg + _weaponEnchant; if (_weaponType != 20 && _weaponType != 62) { // STRボーナス weaponTotalDamage *= 1 + ((_pc.getStr() * 2) / 100d); } else { // DEXボーナス weaponTotalDamage *= 1 + ((_pc.getDex() * _random.nextInt(2)) / 100d); } if (_weaponType == 54 && (_random.nextInt(100) + 1) <= _weaponDoubleDmgChance) { // ダブルヒット // weaponTotalDamage *= 2; weaponTotalDamage += _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; _pc.sendPackets(new S_SkillSound(_pc.getId(), 3398)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3398)); } weaponTotalDamage += calcAttrEnchantDmg(); // 属性強化ダメージボーナス if (_pc.hasSkillEffect(DOUBLE_BRAKE) && (_weaponType == 54 || _weaponType == 58)) { if ((_random.nextInt(100) + 1) <= 40) { weaponTotalDamage *= 1 + (_random.nextDouble() + 0.1d); } } /* * if (_weaponId == 262 && _random.nextInt(100) + 1 <= 75) { // * ディストラクション装備かつ成功確率 // (暫定)75% weaponTotalDamage += * calcDestruction(weaponTotalDamage); } */ double dmg; if (_weaponType != 20 && _weaponType != 62) { dmg = weaponTotalDamage + _statusDamage + _pc.getDmgup() + _pc.getOriginalDmgup(); } else { dmg = weaponTotalDamage + _statusDamage + _pc.getBowDmgup() + _pc.getOriginalBowDmgup(); } if (_weaponType2 == 17) { // キーリンク // if (_pc.getWeapon().getItem().getItemId() == 294 || // _pc.getWeapon().getItem().getItemId() == 305) { dmg = L1WeaponSkill.getKiringkuDamage(_pc, _targetPc); dmg += calcAttrEnchantDmg(); } // ハイネスが回りにいるか for (L1PcInstance target : L1World.getInstance().getVisiblePlayer(_pc, 5)) { if (_pc.getClanid() == target.getClanid() && target.getSubClassId() == 2 && !target.isDead()) { dmg += _random.nextInt(6) + 1; } } // バウンスアタック if (_pc.hasSkillEffect(L1SkillId.BOUNCE_ATTACK_ATKUP)) { dmg += 5; } // 後ろ int back_heading = 0; switch (_targetPc.getHeading()) { case 0: back_heading = 0; break; case 1: back_heading = 1; break; case 2: back_heading = 2; break; case 3: back_heading = 3; break; case 4: back_heading = 4; break; case 5: back_heading = 5; break; case 6: back_heading = 6; break; case 7: back_heading = 7; break; } // 斜め後ろ int tilt_heading[] = new int[2]; switch (_targetPc.getHeading()) { case 0: tilt_heading[0] = 1; tilt_heading[1] = 7; break; case 1: tilt_heading[0] = 0; tilt_heading[1] = 2; break; case 2: tilt_heading[0] = 1; tilt_heading[1] = 3; break; case 3: tilt_heading[0] = 2; tilt_heading[1] = 4; break; case 4: tilt_heading[0] = 3; tilt_heading[1] = 5; break; case 5: tilt_heading[0] = 4; tilt_heading[1] = 6; break; case 6: tilt_heading[0] = 5; tilt_heading[1] = 7; break; case 7: tilt_heading[0] = 0; tilt_heading[1] = 6; break; } // 横 int next_heading[] = new int[2]; switch (_targetPc.getHeading()) { case 0: next_heading[0] = 2; next_heading[1] = 6; break; case 1: next_heading[0] = 7; next_heading[1] = 3; break; case 2: next_heading[0] = 0; next_heading[1] = 4; break; case 3: next_heading[0] = 1; next_heading[1] = 5; break; case 4: next_heading[0] = 2; next_heading[1] = 6; break; case 5: next_heading[0] = 3; next_heading[1] = 7; break; case 6: next_heading[0] = 0; next_heading[1] = 4; break; case 7: next_heading[0] = 1; next_heading[1] = 5; break; } // アサシン if (_weaponType != 20 && _weaponType != 62 || _targetPc.getSubClassId() != 3) { if (_pc.getSubClassId() == 9) { if (_pc.getHeading() == back_heading) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 6091)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 6091)); dmg *= 2; } if (_pc.getHeading() == tilt_heading[0] || _pc.getHeading() == tilt_heading[1]) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 3399)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3399)); dmg *= 1.5d; } if (_pc.getHeading() == next_heading[0] || _pc.getHeading() == next_heading[1]) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 4798)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 4798)); dmg *= 1.2d; } } else { if (_pc.getHeading() == back_heading) { dmg *= 1.25; } if (_pc.getHeading() == tilt_heading[0] || _pc.getHeading() == tilt_heading[1]) { dmg *= 1.15d; } if (_pc.getHeading() == next_heading[0] || _pc.getHeading() == next_heading[1]) { dmg *= 1.1d; } } } // ニンジャ if (_pc.getSubClassId() == 10 && _pc.isInvisble()) { dmg *= 1.25d; } /* * if (_weaponType == 20) { // 弓 if (_arrow != null) { int add_dmg = * _arrow.getItem().getDmgSmall(); if (add_dmg == 0) { add_dmg = 1; } * dmg = dmg + _random.nextInt(add_dmg) + 1; } else if (_weaponId == * 190) { // サイハの弓 dmg = dmg + _random.nextInt(15) + 1; } } else if * (_weaponType == 62) { // ガントトレット int add_dmg = * _sting.getItem().getDmgSmall(); if (add_dmg == 0) { add_dmg = 1; } * dmg = dmg + _random.nextInt(add_dmg) + 1; } */ dmg = calcBuffDamage(dmg); /* * if (_weaponId == 124) { // バフォメットスタッフ dmg += * L1WeaponSkill.getBaphometStaffDamage(_pc, _target); } else if * (_weaponId == 2 || _weaponId == 200002) { // ダイスダガー dmg = * L1WeaponSkill.getDiceDaggerDamage(_pc, _targetPc, weapon); } else if * (_weaponId == 204 || _weaponId == 100204) { // 真紅のクロスボウ * L1WeaponSkill.giveFettersEffect(_pc, _targetPc); } else if (_weaponId * == 264) { // ライトニングエッジ dmg += * L1WeaponSkill.getLightningEdgeDamage(_pc, _target); } else if * (_weaponId == 260 || _weaponId == 263) { // レイジングウィンド、フリージングランサー dmg * += L1WeaponSkill.getAreaSkillWeaponDamage(_pc, _target, _weaponId); } * else if (_weaponId == 261) { // アークメイジスタッフ * L1WeaponSkill.giveArkMageDiseaseEffect(_pc, _target); } else if * (_weaponId == 276 || _weaponId == 277 || _weaponId == 278 || * _weaponId == 279 || _weaponId == 280 || _weaponId == 281) { // * マリスエレメント武器 L1WeaponSkill.getMaliceWeaponDamage(_pc, _target, weapon); * } else { dmg += L1WeaponSkill.getWeaponSkillDamage(_pc, _target, * _weaponId); } */ if (_pc.hasSkillEffect(BURNING_SLASH)) { _pc.sendPackets(new S_SkillSound(_targetPc.getId(), 6591)); _pc.broadcastPacket(new S_SkillSound(_targetPc.getId(), 6591)); _pc.killSkillEffectTimer(BURNING_SLASH); } if (_weaponType == 0) { // 素手 dmg = (_random.nextInt(5) + 4) / 4; } if (_weaponType2 != 17 && _skillId == BONE_BREAK) { dmg += _skillDamage; } if (_weaponType != 20 && _weaponType != 62) { // 防具による追加ダメージ dmg += _pc.getDmgModifierByArmor(); } else { dmg += _pc.getBowDmgModifierByArmor(); } if (_weaponType != 20 && _weaponType != 62) { Object[] dollList = _pc.getDollList().values().toArray(); // マジックドールによる追加ダメージ for (Object dollObject : dollList) { L1DollInstance doll = (L1DollInstance) dollObject; dmg += doll.getDamageByDoll(); } } if (_pc.hasSkillEffect(COOKING_2_0_N) // 料理による追加ダメージ || _pc.hasSkillEffect(COOKING_2_0_S) || _pc.hasSkillEffect(COOKING_3_2_N) || _pc.hasSkillEffect(COOKING_3_2_S)) { if (_weaponType != 20 && _weaponType != 62) { dmg += 1; } } if (_pc.hasSkillEffect(COOKING_2_3_N) // 料理による追加ダメージ || _pc.hasSkillEffect(COOKING_2_3_S) || _pc.hasSkillEffect(COOKING_3_0_N) || _pc.hasSkillEffect(COOKING_3_0_S)) { if (_weaponType == 20 || _weaponType == 62) { dmg += 1; } } // マジェスティ if (_pc.getSubClassId() == 1) { if (_targetPc.isNowHit()) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 4546)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 4546)); Random rnd = new Random(); int parsent = rnd.nextInt(15) + 10; // dmg *= 1 + (parsent / 100d); dmg *= 2; } } // レンジャー if (_pc.getSubClassId() == 5 && _random.nextInt(100) + 1 <= 5) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 7353)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 7353)); dmg += _targetPc.getCurrentHp() * ((_random.nextInt(51) + 10) / 1000d); } int parsent = ((_targetPc.getCon() + _targetPc.getWis())) / 3; if (_targetPc.hasSkillEffect(L1SkillId.SOLID_CARRIAGE) && _random.nextInt(100) + 1 <= parsent) { _targetPc.sendPackets(new S_SkillSound(_targetPc.getId(), 4593)); _targetPc.broadcastPacket(new S_SkillSound(_targetPc.getId(), 4593)); dmg /= 2; } if (_targetPc.getSubClassId() == 12 && _targetPc.getAwakeSkillId() == L1SkillId.AWAKEN_ANTHARAS) { // アンタラス if (_weaponType != 20 && _weaponType != 62) { dmg *= 1.5; } else { dmg *= 0.5; } } else if (_targetPc.getSubClassId() == 12 && _targetPc.getAwakeSkillId() == L1SkillId.AWAKEN_FAFURION) { // パプリオン if (_weaponType != 20 && _weaponType != 62) { dmg *= 0.5; } else { dmg *= 1.5; } } else if (_targetPc.getSubClassId() == 12 && _targetPc.getAwakeSkillId() == L1SkillId.AWAKEN_VALAKAS) { // ヴァラカス if (_weaponType != 20 && _weaponType != 62) { dmg *= 0.5; } else { dmg *= 0.5; } } // サイコ if (_pc.isSaicoSpAttack()) { _pc.setSaicoSpAttack(false); } else if ((_pc.getSubClassId() == 13 && _random.nextInt(100) < 45)) { _targetPc.sendPackets(new S_SkillSound(_targetPc.getId(), 6982)); _targetPc.broadcastPacket(new S_SkillSound(_targetPc.getId(), 6982)); } else { // CONによるダメージ軽減 if (_targetPc.getCon() / 2 > 1) { int calcCon = (int) (_targetPc.getCon() / 1.5d); dmg = dmg - (dmg * ((_random.nextInt(calcCon / 2) + (calcCon / 2)) / 100d)); } dmg -= _targetPc.getDamageReductionByArmor(); // 防具によるダメージ軽減 // TODO マジックドールによるダメージ軽減&回避 Object[] targetDollList = _targetPc.getDollList().values().toArray(); for (Object dollObject : targetDollList) { L1DollInstance doll = (L1DollInstance) dollObject; if (doll.getDamageEvasionByDoll() > 0) { dmg = 0; } dmg -= doll.getDamageReductionByDoll(); } if (_targetPc.hasSkillEffect(COOKING_1_0_S) // 料理によるダメージ軽減 || _targetPc.hasSkillEffect(COOKING_1_1_S) || _targetPc.hasSkillEffect(COOKING_1_2_S) || _targetPc.hasSkillEffect(COOKING_1_3_S) || _targetPc.hasSkillEffect(COOKING_1_4_S) || _targetPc.hasSkillEffect(COOKING_1_5_S) || _targetPc.hasSkillEffect(COOKING_1_6_S) || _targetPc.hasSkillEffect(COOKING_2_0_S) || _targetPc.hasSkillEffect(COOKING_2_1_S) || _targetPc.hasSkillEffect(COOKING_2_2_S) || _targetPc.hasSkillEffect(COOKING_2_3_S) || _targetPc.hasSkillEffect(COOKING_2_4_S) || _targetPc.hasSkillEffect(COOKING_2_5_S) || _targetPc.hasSkillEffect(COOKING_2_6_S) || _targetPc.hasSkillEffect(COOKING_3_0_S) || _targetPc.hasSkillEffect(COOKING_3_1_S) || _targetPc.hasSkillEffect(COOKING_3_2_S) || _targetPc.hasSkillEffect(COOKING_3_3_S) || _targetPc.hasSkillEffect(COOKING_3_4_S) || _targetPc.hasSkillEffect(COOKING_3_5_S) || _targetPc.hasSkillEffect(COOKING_3_6_S)) { dmg -= 5; } if (_targetPc.hasSkillEffect(COOKING_1_7_S) // デザートによるダメージ軽減 || _targetPc.hasSkillEffect(COOKING_2_7_S) || _targetPc.hasSkillEffect(COOKING_3_7_S)) { dmg -= 5; } // ACによるダメージ軽減 /4 int ac = Math.max(0, 10 - _targetPc.getAc()); int ac_redction = 0; if (_targetPc.hasSkillEffect(REDUCTION_ARMOR)) { ac_redction = (int) (ac / 2d); } else { ac_redction = ac / 3; } if (ac_redction >= 2) { dmg -= _random.nextInt(ac_redction / 2) + (ac_redction / 2); } /* * if (_targetPc.hasSkillEffect(REDUCTION_ARMOR)) { int targetPcLvl * = _targetPc.getLevel(); if (targetPcLvl < 50) { targetPcLvl = 50; * } dmg -= (targetPcLvl - 50) / 5 + 1; } */ if (_targetPc.hasSkillEffect(DRAGON_SKIN)) { dmg -= 2; } if (_targetPc.hasSkillEffect(PATIENCE)) { dmg -= 2; } if (_targetPc.hasSkillEffect(IMMUNE_TO_HARM)) { dmg /= 2; } if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) { dmg = 0; } if (_targetPc.hasSkillEffect(ICE_LANCE)) { dmg = 0; } if (_targetPc.hasSkillEffect(FREEZING_BLIZZARD)) { dmg = 0; } if (_targetPc.hasSkillEffect(FREEZING_BREATH)) { dmg = 0; } if (_targetPc.hasSkillEffect(EARTH_BIND)) { dmg = 0; } if (dmg <= 0) { _isHit = false; _drainHp = 0; // ダメージ無しの場合は吸収による回復はしない } } // MOD効果 W_DoMod wa = new W_DoMod(_pc, _targetPc, dmg); // シャドウナイト範囲 if (_pc.getSubClassId() == 4 && _random.nextInt(100) + 1 <= 65) { _targetPc.sendPackets(new S_SkillSound(_targetPc.getId(), 4581)); _targetPc.broadcastPacket(new S_SkillSound(_targetPc.getId(), 4581)); for (L1PcInstance tgtPc : L1World.getInstance().getVisiblePlayer(_pc, 2)) { if (_pc.getClanid() != tgtPc.getClanid() && !tgtPc.isDead() && _targetPc.getId() != tgtPc.getId()) { int damage = 0; if (_pc.getWeapon() != null) { W_Method wm = new W_Method(); damage = wm.weaponBasicValue(_pc, _pc.getWeapon()); damage = W_Method.getCalcPcReduction(tgtPc, damage); } else { damage = 1; } tgtPc.receiveDamage(_pc, damage, false); } } } // ハンター範囲 if (_pc.getSubClassId() == 11) { /* * int targetCount = _random.nextInt(3) + 1; for (L1PcInstance tgtPc * : L1World.getInstance().getVisiblePlayer(_targetPc, 2)) { if * (targetCount == 0) { break; } if (_pc.getClanid() != * tgtPc.getClanid() && !tgtPc.isDead() && _targetPc.getId() != * tgtPc.getId()) { _pc.sendPackets(new S_UseAttackSkill(_pc, tgtPc, * 4794, false)); _pc.broadcastPacket(new S_UseAttackSkill(_pc, * tgtPc, 4794, false)); int damage = 0; if (_pc.getWeapon() != * null) { W_Method wm = new W_Method(); damage = * wm.weaponBasicValue(_pc, _pc.getWeapon()); damage = * W_Method.getCalcPcReduction(tgtPc, damage); } else { damage = 1; * } tgtPc.receiveDamage(_pc, damage, false); } targetCount--; } */ if (_random.nextInt(100) + 1 <= 30 && !_targetPc.hasSkillEffect(L1SkillId.HUNTER_PAIN)) { S_EffectLocation packet = new S_EffectLocation(_targetPc.getX(), _targetPc.getY(), 7681); _targetPc.sendPackets(packet); _targetPc.broadcastPacket(packet); _targetPc.setSkillEffect(L1SkillId.HUNTER_PAIN, 2000); _targetPc.set_hunterPainPlayer(_pc); }/* * else if (_targetPc.hasSkillEffect(L1SkillId.HUNTER_PAIN)) { * synchronized (this) { if (_targetPc.get_hunterPainDamage() < * 1000) { * _targetPc.set_hunterPainDamage(_targetPc.get_hunterPainDamage() + * (int) (dmg / 2)); } } } */ } // フェンリル-アンタラス if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_ANTHARAS) { _pc.setCurrentHp((_pc.getCurrentHp() + (int) (dmg / 2))); } if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_ANTHARAS && _random.nextInt(100) + 1 <= 8) { // アンタラス アースメテオ _pc.sendPackets(new S_SkillSound(_pc.getId(), 7361)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 7361)); for (L1PcInstance tgtPc : L1World.getInstance().getVisiblePlayer(_pc, 12)) { if (_pc.getClanid() != tgtPc.getClanid() && !tgtPc.isDead()) { int damage = 0; if (_pc.getWeapon() != null) { W_Method wm = new W_Method(); damage = wm.weaponBasicValue(_pc, _pc.getWeapon()); damage = W_Method.getCalcPcReduction(tgtPc, damage); } else { damage = 1; } tgtPc.receiveDamage(_pc, damage, false); } } } else if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_FAFURION && _random.nextInt(100) + 1 <= 8) { // パプリオン アイスメテオ _pc.sendPackets(new S_SkillSound(_pc.getId(), 7771)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 7771)); for (L1PcInstance tgtPc : L1World.getInstance().getVisiblePlayer(_pc, 12)) { if (_pc.getClanid() != tgtPc.getClanid() && !tgtPc.isDead()) { int damage = 0; if (_pc.getWeapon() != null) { W_Method wm = new W_Method(); damage = wm.weaponBasicValue(_pc, _pc.getWeapon()); damage = W_Method.getCalcPcReduction(tgtPc, damage); } else { damage = 1; } tgtPc.receiveDamage(_pc, damage, false); } } } else if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_VALAKAS && _random.nextInt(100) + 1 <= 8) { // ヴァラカス ダークメテオ _pc.sendPackets(new S_SkillSound(_pc.getId(), 4539)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 4539)); for (L1PcInstance tgtPc : L1World.getInstance().getVisiblePlayer(_pc, 12)) { if (_pc.getClanid() != tgtPc.getClanid() && !tgtPc.isDead()) { int damage = 0; if (_pc.getWeapon() != null) { W_Method wm = new W_Method(); damage = wm.weaponBasicValue(_pc, _pc.getWeapon()); damage = W_Method.getCalcPcReduction(tgtPc, damage); } else { damage = 1; } tgtPc.receiveDamage(_pc, damage, false); } } } // 攻撃エフェクト if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_ANTHARAS) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 213)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 213)); } else if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_FAFURION) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 215)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 215)); } else if (_pc.getSubClassId() == 12 && _pc.getAwakeSkillId() == L1SkillId.AWAKEN_VALAKAS) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 214)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 214)); } if (_pc.getSubClassId() == 14 && _random.nextInt(100) + 1 <= 10 && !_targetPc.hasSkillEffect(L1SkillId.SHOCK_STUN)) { int stunTime = (_random.nextInt(11) + 10) * 100; int shockStunDuration = stunTime; L1EffectSpawn.getInstance().spawnEffect(81162, shockStunDuration, _targetPc.getX(), _targetPc.getY(), _targetPc.getMapId()); _targetPc.sendPackets(new S_Paralysis(S_Paralysis.TYPE_STUN, true)); _targetPc.setSkillEffect(L1SkillId.SHOCK_STUN, shockStunDuration); } // 攻撃回数のカウント if (WarTimeController.getInstance().isNowWar(1)) { if (_pc.getWeapon() != null) { if (_pc.getWeapon().getItem().getType1() != 20 && _pc.getWeapon().getItem().getType1() != 62) { _pc.setNearAttackCount(_pc.getNearAttackCount() + 1); } else { _pc.setDistanceAttackCount(_pc.getDistanceAttackCount() + 1); } } } return (int) dmg; } // ●●●● プレイヤー から NPC へのダメージ算出 ●●●● private int calcPcNpcDamage() { int weaponMaxDamage = _weaponLarge; /* * if (_targetNpc.getNpcTemplate().get_size().equalsIgnoreCase("small") * && _weaponSmall > 0) { weaponMaxDamage = _weaponSmall; } else if * (_targetNpc.getNpcTemplate().get_size().equalsIgnoreCase("large") && * _weaponLarge > 0) { weaponMaxDamage = _weaponLarge; } */ int weaponDamage = 0; if (_weaponType == 58 && (_random.nextInt(100) + 1) <= _weaponDoubleDmgChance) { // クリティカルヒット weaponDamage = weaponMaxDamage; _pc.sendPackets(new S_SkillSound(_pc.getId(), 3671)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3671)); } else if (_weaponType == 0) {// || _weaponType == 20 || _weaponType == // 62) { // 素手 // 、 // 弓 // 、 // ガントトレット weaponDamage = 0; } else { // レンジャー if (_pc.getSubClassId() == 5) { weaponMaxDamage *= 2; _weaponSmall *= 2; weaponDamage = _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; } else { weaponDamage = _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; } } if (_pc.hasSkillEffect(SOUL_OF_FLAME) && _random.nextInt(100) + 1 <= 20) { if (_weaponType != 20 && _weaponType != 62) { weaponDamage = weaponMaxDamage; } } int weaponTotalDamage = weaponDamage + _weaponAddDmg + _weaponEnchant; weaponTotalDamage += calcMaterialBlessDmg(); // 銀祝福ダメージボーナス if (_weaponType == 54 && (_random.nextInt(100) + 1) <= _weaponDoubleDmgChance) { // ダブルヒット weaponTotalDamage += _random.nextInt(weaponMaxDamage - _weaponSmall) + _weaponSmall; _pc.sendPackets(new S_SkillSound(_pc.getId(), 3398)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 3398)); } weaponTotalDamage += calcAttrEnchantDmg(); // 属性強化ダメージボーナス if (_pc.hasSkillEffect(DOUBLE_BRAKE) && (_weaponType == 54 || _weaponType == 58)) { if ((_random.nextInt(100) + 1) <= 33) { weaponTotalDamage *= 2; } } /* * if (_weaponId == 262 && _random.nextInt(100) + 1 <= 75) { // * ディストラクション装備かつ成功確率 // (暫定)75% weaponTotalDamage += * calcDestruction(weaponTotalDamage); } */ double dmg; if (_weaponType != 20 && _weaponType != 62) { dmg = weaponTotalDamage + _statusDamage + _pc.getDmgup() + _pc.getOriginalDmgup(); // STRボーナス dmg *= 1 + ((_pc.getStr() * 2) / 100); } else { dmg = weaponTotalDamage + _statusDamage + _pc.getBowDmgup() + _pc.getOriginalBowDmgup(); // DEXボーナス if (_weaponType == 62) { dmg *= 1 + ((_pc.getStr() * 2) / 100); } else { dmg *= 1 + ((_pc.getDex() * 2) / 100); } } /* * if (_weaponType == 20) { // 弓 if (_arrow != null) { int add_dmg = 0; * if (_targetNpc.getNpcTemplate().get_size().equalsIgnoreCase("large")) * { add_dmg = _arrow.getItem().getDmgLarge(); } else { add_dmg = * _arrow.getItem().getDmgSmall(); } if (add_dmg == 0) { add_dmg = 1; } * if (_targetNpc.getNpcTemplate().is_hard()) { add_dmg /= 2; } dmg = * dmg + _random.nextInt(add_dmg) + 1; } else if (_weaponId == 190) { // * サイハの弓 dmg = dmg + _random.nextInt(15) + 1; } } else if (_weaponType * == 62) { // ガントトレット int add_dmg = 0; if * (_targetNpc.getNpcTemplate().get_size().equalsIgnoreCase("large")) { * add_dmg = _sting.getItem().getDmgLarge(); } else { add_dmg = * _sting.getItem().getDmgSmall(); } if (add_dmg == 0) { add_dmg = 1; } * dmg = dmg + _random.nextInt(add_dmg) + 1; } */ dmg = calcBuffDamage(dmg); /* * if (_weaponId == 124) { // バフォメットスタッフ dmg += * L1WeaponSkill.getBaphometStaffDamage(_pc, _target); } else if * (_weaponId == 204 || _weaponId == 100204) { // 真紅のクロスボウ * L1WeaponSkill.giveFettersEffect(_pc, _targetNpc); } else if * (_weaponId == 264) { // ライトニングエッジ dmg += * L1WeaponSkill.getLightningEdgeDamage(_pc, _target); } else if * (_weaponId == 260 || _weaponId == 263) { // レイジングウィンド、フリージングランサー dmg * += L1WeaponSkill.getAreaSkillWeaponDamage(_pc, _target, _weaponId); } * else if (_weaponId == 261) { // アークメイジスタッフ * L1WeaponSkill.giveArkMageDiseaseEffect(_pc, _target); } else if * (_weaponId == 276 || _weaponId == 277 || _weaponId == 278 || * _weaponId == 279 || _weaponId == 280 || _weaponId == 281) { // * マリスエレメント武器 L1WeaponSkill.getMaliceWeaponDamage(_pc, _target, weapon); * } else { dmg += L1WeaponSkill.getWeaponSkillDamage(_pc, _target, * _weaponId); } */ if (_pc.hasSkillEffect(BURNING_SLASH)) { _pc.sendPackets(new S_SkillSound(_targetNpc.getId(), 6591)); _pc.broadcastPacket(new S_SkillSound(_targetNpc.getId(), 6591)); _pc.killSkillEffectTimer(BURNING_SLASH); } if (_weaponType == 0) { // 素手 dmg = (_random.nextInt(5) + 4) / 4; } if (_weaponType2 != 17 && _skillId == BONE_BREAK) { dmg += _skillDamage; } if (_weaponType2 == 17) { // キーリンク // if (_pc.getWeapon().getItem().getItemId() == 294 || // _pc.getWeapon().getItem().getItemId() == 305) { dmg = L1WeaponSkill.getKiringkuDamage(_pc, _target); dmg += calcAttrEnchantDmg(); } if (_weaponType != 20 && _weaponType != 62) { // 防具による追加ダメージ dmg += _pc.getDmgModifierByArmor(); } else { dmg += _pc.getBowDmgModifierByArmor(); } if (_weaponType != 20 && _weaponType != 62) { Object[] dollList = _pc.getDollList().values().toArray(); // マジックドールによる追加ダメージ for (Object dollObject : dollList) { L1DollInstance doll = (L1DollInstance) dollObject; dmg += doll.getDamageByDoll(); } } if (_pc.hasSkillEffect(COOKING_2_0_N) // 料理による追加ダメージ || _pc.hasSkillEffect(COOKING_2_0_S) || _pc.hasSkillEffect(COOKING_3_2_N) || _pc.hasSkillEffect(COOKING_3_2_S)) { if (_weaponType != 20 && _weaponType != 62) { dmg += 1; } } if (_pc.hasSkillEffect(COOKING_2_3_N) // 料理による追加ダメージ || _pc.hasSkillEffect(COOKING_2_3_S) || _pc.hasSkillEffect(COOKING_3_0_N) || _pc.hasSkillEffect(COOKING_3_0_S)) { if (_weaponType == 20 || _weaponType == 62) { dmg += 1; } } dmg -= calcNpcDamageReduction(); /* * // プレイヤーからペット、サモンに攻撃 boolean isNowWar = false; int castleId = * L1CastleLocation.getCastleIdByArea(_targetNpc); if (castleId > 0) { * isNowWar = WarTimeController.getInstance().isNowWar(castleId); } if * (!isNowWar) { if (_targetNpc instanceof L1PetInstance) { dmg /= 8; } * if (_targetNpc instanceof L1SummonInstance) { L1SummonInstance summon * = (L1SummonInstance) _targetNpc; if (summon.isExsistMaster()) { dmg * /= 8; } } } */ if (_targetNpc.hasSkillEffect(ICE_LANCE)) { dmg = 0; } if (_targetNpc.hasSkillEffect(FREEZING_BLIZZARD)) { dmg = 0; } if (_targetNpc.hasSkillEffect(FREEZING_BREATH)) { dmg = 0; } if (_targetNpc.hasSkillEffect(EARTH_BIND)) { dmg = 0; } if (dmg <= 0) { _isHit = false; _drainHp = 0; // ダメージ無しの場合は吸収による回復はしない } // MOD効果 W_DoMod wa = new W_DoMod(_pc, _targetNpc, dmg); return (int) dmg; } // ●●●● NPC から プレイヤー へのダメージ算出 ●●●● private int calcNpcPcDamage() { int lvl = _npc.getLevel(); double dmg = 0D; if (lvl < 10) { dmg = _random.nextInt(lvl) + 10D + _npc.getStr() / 2 + 1; } else { dmg = _random.nextInt(lvl) + _npc.getStr() / 2 + 1; } if (_npc instanceof L1PetInstance) { dmg += (lvl / 16); // ペットはLV16毎に追加打撃 dmg += ((L1PetInstance) _npc).getDamageByWeapon(); } dmg += _npc.getDmgup(); if (isUndeadDamage()) { dmg *= 1.1; } dmg = dmg * getLeverage() / 10; dmg -= calcPcDefense(); if (_npc.isWeaponBreaked()) { // NPCがウェポンブレイク中。 dmg /= 2; } if (_targetPc.hasSkillEffect(L1SkillId.SOLID_CARRIAGE) && _random.nextInt(100) + 1 <= (_targetPc.getCon() / 3)) { _targetPc.sendPackets(new S_SkillSound(_targetPc.getId(), 4593)); _targetPc.broadcastPacket(new S_SkillSound(_targetPc.getId(), 4593)); dmg /= 2; } dmg -= _targetPc.getDamageReductionByArmor(); // 防具によるダメージ軽減 // TODO マジックドールによるダメージ軽減&回避 Object[] targetDollList = _targetPc.getDollList().values().toArray(); for (Object dollObject : targetDollList) { L1DollInstance doll = (L1DollInstance) dollObject; if (doll.getDamageEvasionByDoll() > 0) { dmg = 0; } dmg -= doll.getDamageReductionByDoll(); } if (_targetPc.hasSkillEffect(COOKING_1_0_S) // 料理によるダメージ軽減 || _targetPc.hasSkillEffect(COOKING_1_1_S) || _targetPc.hasSkillEffect(COOKING_1_2_S) || _targetPc.hasSkillEffect(COOKING_1_3_S) || _targetPc.hasSkillEffect(COOKING_1_4_S) || _targetPc.hasSkillEffect(COOKING_1_5_S) || _targetPc.hasSkillEffect(COOKING_1_6_S) || _targetPc.hasSkillEffect(COOKING_2_0_S) || _targetPc.hasSkillEffect(COOKING_2_1_S) || _targetPc.hasSkillEffect(COOKING_2_2_S) || _targetPc.hasSkillEffect(COOKING_2_3_S) || _targetPc.hasSkillEffect(COOKING_2_4_S) || _targetPc.hasSkillEffect(COOKING_2_5_S) || _targetPc.hasSkillEffect(COOKING_2_6_S) || _targetPc.hasSkillEffect(COOKING_3_0_S) || _targetPc.hasSkillEffect(COOKING_3_1_S) || _targetPc.hasSkillEffect(COOKING_3_2_S) || _targetPc.hasSkillEffect(COOKING_3_3_S) || _targetPc.hasSkillEffect(COOKING_3_4_S) || _targetPc.hasSkillEffect(COOKING_3_5_S) || _targetPc.hasSkillEffect(COOKING_3_6_S)) { dmg -= 5; } if (_targetPc.hasSkillEffect(COOKING_1_7_S) // デザートによるダメージ軽減 || _targetPc.hasSkillEffect(COOKING_2_7_S) || _targetPc.hasSkillEffect(COOKING_3_7_S)) { dmg -= 5; } if (_targetPc.hasSkillEffect(REDUCTION_ARMOR)) { int targetPcLvl = _targetPc.getLevel(); if (targetPcLvl < 50) { targetPcLvl = 50; } dmg -= (targetPcLvl - 50) / 5 + 1; } if (_targetPc.hasSkillEffect(DRAGON_SKIN)) { dmg -= 2; } if (_targetPc.hasSkillEffect(PATIENCE)) { dmg -= 2; } if (_targetPc.hasSkillEffect(IMMUNE_TO_HARM)) { dmg /= 2; } if (_targetPc.hasSkillEffect(ABSOLUTE_BARRIER)) { dmg = 0; } if (_targetPc.hasSkillEffect(ICE_LANCE)) { dmg = 0; } if (_targetPc.hasSkillEffect(FREEZING_BLIZZARD)) { dmg = 0; } if (_targetPc.hasSkillEffect(FREEZING_BREATH)) { dmg = 0; } if (_targetPc.hasSkillEffect(EARTH_BIND)) { dmg = 0; } // ペット、サモンからプレイヤーに攻撃 boolean isNowWar = false; int castleId = L1CastleLocation.getCastleIdByArea(_targetPc); if (castleId > 0) { isNowWar = WarTimeController.getInstance().isNowWar(castleId); } if (!isNowWar) { if (_npc instanceof L1PetInstance) { dmg /= 8; } if (_npc instanceof L1SummonInstance) { L1SummonInstance summon = (L1SummonInstance) _npc; if (summon.isExsistMaster()) { dmg /= 8; } } } if (dmg <= 0) { _isHit = false; } addNpcPoisonAttack(_npc, _targetPc); return (int) dmg; } // ●●●● NPC から NPC へのダメージ算出 ●●●● private int calcNpcNpcDamage() { int lvl = _npc.getLevel(); double dmg = 0; if (_npc instanceof L1PetInstance) { dmg = _random.nextInt(_npc.getNpcTemplate().get_level()) + _npc.getStr() / 2 + 1; dmg += (lvl / 16); // ペットはLV16毎に追加打撃 dmg += ((L1PetInstance) _npc).getDamageByWeapon(); } else { dmg = _random.nextInt(lvl) + _npc.getStr() / 2 + 1; } if (isUndeadDamage()) { dmg *= 1.1; } dmg = dmg * getLeverage() / 10; dmg -= calcNpcDamageReduction(); if (_npc.isWeaponBreaked()) { // NPCがウェポンブレイク中。 dmg /= 2; } addNpcPoisonAttack(_npc, _targetNpc); if (_targetNpc.hasSkillEffect(ICE_LANCE)) { dmg = 0; } if (_targetNpc.hasSkillEffect(FREEZING_BLIZZARD)) { dmg = 0; } if (_targetNpc.hasSkillEffect(FREEZING_BREATH)) { dmg = 0; } if (_targetNpc.hasSkillEffect(EARTH_BIND)) { dmg = 0; } if (dmg <= 0) { _isHit = false; } // シャドウナイト範囲 if (_pc.getSubClassId() == 4 && _random.nextInt(100) + 1 <= 50) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 4581)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 4581)); for (L1Object obj : L1World.getInstance().getVisibleObjects(_pc, 2)) { if (obj instanceof L1NpcInstance) { L1NpcInstance tgtNPc = (L1NpcInstance) obj; if (!tgtNPc.isDead()) { int damage = 0; if (_pc.getWeapon() != null) { W_Method wm = new W_Method(); damage = wm.weaponBasicValue(_pc, _pc.getWeapon()); } else { damage = 1; } tgtNPc.receiveDamage(_pc, damage); } } } } return (int) dmg; } // ●●●● プレイヤーのダメージ強化魔法 ●●●● private double calcBuffDamage(double dmg) { // 火武器、バーサーカーのダメージは1.5倍しない if (_pc.hasSkillEffect(BURNING_SPIRIT) || (_pc.hasSkillEffect(ELEMENTAL_FIRE) && _weaponType != 20 && _weaponType != 62 && _weaponType2 != 17)) { if ((_random.nextInt(100) + 1) <= 33) { double tempDmg = dmg; if (_pc.hasSkillEffect(FIRE_WEAPON)) { tempDmg -= 4; } if (_pc.hasSkillEffect(FIRE_BLESS)) { tempDmg -= 4; } if (_pc.hasSkillEffect(BURNING_WEAPON)) { tempDmg -= 6; } if (_pc.hasSkillEffect(BERSERKERS)) { tempDmg -= 5; } double diffDmg = dmg - tempDmg; dmg = tempDmg * 1.5d + diffDmg; } } // チェーンソードによる弱点露出 if (_pc.isFoeSlayer()) { if (_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV1)) { if (_pc.getSubClassId() == 11) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 1054)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 1054)); dmg += 8; } else { dmg += 3; } if (W_Method.modValue(weapon, 31) != 0) { dmg += W_Method.modValue(weapon, 31) / 5; } } else if (_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV2)) { if (_pc.getSubClassId() == 11) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 1054)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 1054)); dmg += 14; } else { dmg += 6; } if (W_Method.modValue(weapon, 31) != 0) { dmg += W_Method.modValue(weapon, 31) / 5; } } else if (_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV3)) { if (_pc.getSubClassId() == 11) { _pc.sendPackets(new S_SkillSound(_pc.getId(), 1054)); _pc.broadcastPacket(new S_SkillSound(_pc.getId(), 1054)); dmg += 20; } else { dmg += 9; } if (W_Method.modValue(weapon, 31) != 0) { dmg += W_Method.modValue(weapon, 31) / 5; } } } else if ((_pc.getSubClassId() == 11 && (_random.nextInt(100) + 1) <= _weaponWeaknessExposureChance) || (_pc.getSubClassId() != 11 && _weaponType2 == 18 && (_random.nextInt(100) + 1) <= _weaponWeaknessExposureChance)) { if (_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV1)) { _pc.killSkillEffectTimer(STATUS_WEAKNESS_EXPOSURE_LV1); _pc.removeSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV1); _pc.setSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV2, 15000); _pc.sendPackets(new S_SkillIconGFX(75, 2)); } else if (_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV2)) { _pc.killSkillEffectTimer(STATUS_WEAKNESS_EXPOSURE_LV2); _pc.removeSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV2); _pc.setSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV3, 15000); _pc.sendPackets(new S_SkillIconGFX(75, 3)); } else if (!_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV2) && !_pc.hasSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV3)) { _pc.setSkillEffect(STATUS_WEAKNESS_EXPOSURE_LV1, 15000); _pc.sendPackets(new S_SkillIconGFX(75, 1)); } } // バーニングスラッシュ if (_pc.hasSkillEffect(BURNING_SLASH)) { dmg += _random.nextInt(20) + 20; } return dmg; } // ●●●● プレイヤーのACによるダメージ軽減 ●●●● private int calcPcDefense() { int ac = Math.max(0, 10 - _targetPc.getAc()); int acDefMax = _targetPc.getClassFeature().getAcDefenseMax(ac); return _random.nextInt(acDefMax + 1); } // ●●●● NPCのダメージリダクションによる軽減 ●●●● private int calcNpcDamageReduction() { return _targetNpc.getNpcTemplate().get_damagereduction(); } // ●●●● 武器の材質と祝福による追加ダメージ算出 ●●●● private int calcMaterialBlessDmg() { int damage = 0; int undead = _targetNpc.getNpcTemplate().get_undead(); if ((_weaponMaterial == 14 || _weaponMaterial == 17 || _weaponMaterial == 22) && (undead == 1 || undead == 3 || undead == 5)) { // 銀・ミスリル・オリハルコン、かつ、アンデッド系・アンデッド系ボス・銀特効モンスター damage += _random.nextInt(20) + 1; } if ((_weaponMaterial == 17 || _weaponMaterial == 22) && undead == 2) { // ミスリル・オリハルコン、かつ、悪魔系 damage += _random.nextInt(3) + 1; } if (_weaponBless == 0 && (undead == 1 || undead == 2 || undead == 3)) { // 祝福武器、かつ、アンデッド系・悪魔系・アンデッド系ボス damage += _random.nextInt(4) + 1 + 2; } if (_pc.getWeapon() != null && _weaponType != 20 && _weaponType != 62 && weapon.getHolyDmgByMagic() != 0 && (undead == 1 || undead == 3)) { damage += weapon.getHolyDmgByMagic(); } return damage; } // ●●●● 武器の属性強化による追加ダメージ算出 ●●●● private int calcAttrEnchantDmg() { int damage = 0; // int weakAttr = _targetNpc.getNpcTemplate().get_weakAttr(); // if ((weakAttr & 1) == 1 && _weaponAttrEnchantKind == 1 // 地 // || (weakAttr & 2) == 2 && _weaponAttrEnchantKind == 2 // 火 // || (weakAttr & 4) == 4 && _weaponAttrEnchantKind == 4 // 水 // || (weakAttr & 8) == 8 && _weaponAttrEnchantKind == 8) { // 風 // damage = _weaponAttrEnchantLevel; // } if (_weaponAttrEnchantLevel == 1) { damage = 1; } else if (_weaponAttrEnchantLevel == 2) { damage = 3; } else if (_weaponAttrEnchantLevel == 3) { damage = 5; } // XXX 耐性処理は本来、耐性合計値ではなく、各値を個別に処理して総和する。 int resist = 0; if (_calcType == PC_PC) { if (_weaponAttrEnchantKind == 1) { // 地 resist = _targetPc.getEarth(); } else if (_weaponAttrEnchantKind == 2) { // 火 resist = _targetPc.getFire(); } else if (_weaponAttrEnchantKind == 4) { // 水 resist = _targetPc.getWater(); } else if (_weaponAttrEnchantKind == 8) { // 風 resist = _targetPc.getWind(); } } else if (_calcType == PC_NPC) { int weakAttr = _targetNpc.getNpcTemplate().get_weakAttr(); if ((_weaponAttrEnchantKind == 1 && weakAttr == 1) // 地 || (_weaponAttrEnchantKind == 2 && weakAttr == 2) // 火 || (_weaponAttrEnchantKind == 4 && weakAttr == 4) // 水 || (_weaponAttrEnchantKind == 8 && weakAttr == 8)) { // 風 resist = -50; } } int resistFloor = (int) (0.32 * Math.abs(resist)); if (resist >= 0) { resistFloor *= 1; } else { resistFloor *= -1; } double attrDeffence = resistFloor / 32.0; double attrCoefficient = 1 - attrDeffence; damage *= attrCoefficient; return damage; } // ●●●● NPCのアンデッドの夜間攻撃力の変化 ●●●● private boolean isUndeadDamage() { boolean flag = false; int undead = _npc.getNpcTemplate().get_undead(); boolean isNight = L1GameTimeClock.getInstance().currentTime().isNight(); if (isNight && (undead == 1 || undead == 3 || undead == 4)) { // 18〜6時、かつ // 、 // アンデッド系・アンデッド系ボス・弱点無効のアンデッド系 flag = true; } return flag; } // ●●●● NPCの毒攻撃を付加 ●●●● private void addNpcPoisonAttack(L1Character attacker, L1Character target) { if (_npc.getNpcTemplate().get_poisonatk() != 0) { // 毒攻撃あり if (15 >= _random.nextInt(100) + 1) { // 15%の確率で毒攻撃 if (_npc.getNpcTemplate().get_poisonatk() == 1) { // 通常毒 // 3秒周期でダメージ5 L1DamagePoison.doInfection(attacker, target, 3000, 5); } else if (_npc.getNpcTemplate().get_poisonatk() == 2) { // 沈黙毒 L1SilencePoison.doInfection(target); } else if (_npc.getNpcTemplate().get_poisonatk() == 4) { // 麻痺毒 // 20秒後に45秒間麻痺 L1ParalysisPoison.doInfection(target, 20000, 45000); } } } else if (_npc.getNpcTemplate().get_paralysisatk() != 0) { // 麻痺攻撃あり } } // ■■■■ マナスタッフ、鋼鉄のマナスタッフ、マナバーラードのMP吸収量算出 ■■■■ public void calcStaffOfMana() { if (_weaponId == 126 || _weaponId == 127) { // SOMまたは鋼鉄のSOM int som_lvl = _weaponEnchant + 3; // 最大MP吸収量を設定 if (som_lvl < 0) { som_lvl = 0; } // MP吸収量をランダム取得 _drainMana = _random.nextInt(som_lvl) + 1; // 最大MP吸収量を9に制限 if (_drainMana > Config.MANA_DRAIN_LIMIT_PER_SOM_ATTACK) { _drainMana = Config.MANA_DRAIN_LIMIT_PER_SOM_ATTACK; } } else if (_weaponId == 259) { // マナバーラード if (_calcType == PC_PC) { if (_targetPc.getMr() <= _random.nextInt(100) + 1) { // 確率はターゲットのMRに依存 _drainMana = 1; // 吸収量は1固定 } } else if (_calcType == PC_NPC) { if (_targetNpc.getMr() <= _random.nextInt(100) + 1) { // 確率はターゲットのMRに依存 _drainMana = 1; // 吸収量は1固定 } } } } // ■■■■ ディストラクションのHP吸収量算出 ■■■■ private int calcDestruction(int dmg) { _drainHp = (dmg / 8) + 1; if (_drainHp <= 0) { _drainHp = 1; } return _drainHp; } // ■■■■ PCの毒攻撃を付加 ■■■■ public void addPcPoisonAttack(L1Character attacker, L1Character target) { int chance = _random.nextInt(100) + 1; // TODO マジックドールによる毒付与 start Object[] dollList = _pc.getDollList().values().toArray(); for (Object dollObject : dollList) { L1DollInstance doll = (L1DollInstance) dollObject; if (doll.getPoisonByDoll() > 0) { // 通常毒、3秒周期、ダメージHP-5 L1DamagePoison.doInfection(attacker, target, 3000, 5); } } // TODO マジックドールによる毒付与 end if ((_weaponId == 13 || _weaponId == 44 // FOD、古代のダークエルフソード || (_weaponId != 0 && _pc.hasSkillEffect(ENCHANT_VENOM))) // エンチャント // ベノム中 && chance <= 10) { // 通常毒、3秒周期、ダメージHP-5 L1DamagePoison.doInfection(attacker, target, 3000, 5); } } // ■■■■ チェイサーによる攻撃を付加 ■■■■ public void addChaserAttack() { if (5 > _random.nextInt(100) + 1) { if (_weaponId == 265 || _weaponId == 266 || _weaponId == 267 || _weaponId == 268) { // テーベ武器 L1Chaser chaser = new L1Chaser(_pc, _target, L1Skills.ATTR_EARTH, 7025); chaser.begin(); } else if (_weaponId == 282 || _weaponId == 283) { // ククルカン武器 L1Chaser chaser = new L1Chaser(_pc, _target, L1Skills.ATTR_WATER, 7179); chaser.begin(); } } } /* ■■■■■■■■■■■■■■ 攻撃モーション送信 ■■■■■■■■■■■■■■ */ public void action() { if (_calcType == PC_PC || _calcType == PC_NPC) { actionPc(); } else if (_calcType == NPC_PC || _calcType == NPC_NPC) { actionNpc(); } } // ●●●● プレイヤーの攻撃モーション送信 ●●●● private void actionPc() { _pc.setHeading(_pc.targetDirection(_targetX, _targetY)); // 向きのセット if (_weaponType == 20) { /* * if (_arrow != null) { // 矢がある場合 _pc.sendPackets(new * S_UseArrowSkill(_pc, _targetId, 66, _targetX, _targetY, _isHit)); * _pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId, 66, * _targetX, _targetY, _isHit)); if (_isHit) { * _target.broadcastPacketExceptTargetSight(new * S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _pc); } * _pc.getInventory().removeItem(_arrow, 1); } else if (_weaponId == * 190) { // 矢が無くてサイハの場合 _pc.sendPackets(new S_UseArrowSkill(_pc, * _targetId, 2349, _targetX, _targetY, _isHit)); * _pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId, 2349, * _targetX, _targetY, _isHit)); if (_isHit) { * _target.broadcastPacketExceptTargetSight(new * S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _pc); } } */ _pc.sendPackets(new S_UseArrowSkill(_pc, _targetId, 6784, _targetX, _targetY, _isHit)); _pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId, 6784, _targetX, _targetY, _isHit)); if (_isHit) { _target.broadcastPacketExceptTargetSight(new S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _pc); if (W_Method.modValue(_pc.getWeapon(), 20) != 0) { // アロー魔法 if (_pc.getWeapon() != null && _random.nextInt(100) < W_Method.modValue(_pc.getWeapon(), 20)) { W_DoMod wd = new W_DoMod(_pc, _target, 0); wd.proc_ArrowSkill(); } } } } else if (_weaponType == 62) {// && _sting != null) { // ガントレット /* * _pc.sendPackets(new S_UseArrowSkill(_pc, _targetId, 2989, * _targetX, _targetY, _isHit)); _pc.broadcastPacket(new * S_UseArrowSkill(_pc, _targetId, 2989, _targetX, _targetY, * _isHit)); */ _pc.sendPackets(new S_UseArrowSkill(_pc, _targetId, 6767, _targetX, _targetY, _isHit)); _pc.broadcastPacket(new S_UseArrowSkill(_pc, _targetId, 6767, _targetX, _targetY, _isHit)); if (_isHit) { _target.broadcastPacketExceptTargetSight(new S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _pc); } // _pc.getInventory().removeItem(_sting, 1); } else { if (_isHit) { _pc.sendPackets(new S_AttackPacket(_pc, _targetId, ActionCodes.ACTION_Attack)); _pc.broadcastPacket(new S_AttackPacket(_pc, _targetId, ActionCodes.ACTION_Attack)); _target.broadcastPacketExceptTargetSight(new S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _pc); } else { if (_targetId > 0) { _pc.sendPackets(new S_AttackMissPacket(_pc, _targetId)); _pc.broadcastPacket(new S_AttackMissPacket(_pc, _targetId)); } else { _pc.sendPackets(new S_AttackPacket(_pc, 0, ActionCodes.ACTION_Attack)); _pc.broadcastPacket(new S_AttackPacket(_pc, 0, ActionCodes.ACTION_Attack)); } } } } // ●●●● NPCの攻撃モーション送信 ●●●● private void actionNpc() { int _npcObjectId = _npc.getId(); int bowActId = 0; int actId = 0; _npc.setHeading(_npc.targetDirection(_targetX, _targetY)); // 向きのセット // ターゲットとの距離が2以上あれば遠距離攻撃 boolean isLongRange = (_npc.getLocation().getTileLineDistance(new Point(_targetX, _targetY)) > 1); bowActId = _npc.getNpcTemplate().getBowActId(); if (getActId() > 0) { actId = getActId(); } else { actId = ActionCodes.ACTION_Attack; } // 距離が2以上、攻撃者の弓のアクションIDがある場合は遠攻撃 if (isLongRange && bowActId > 0) { _npc.broadcastPacket(new S_UseArrowSkill(_npc, _targetId, bowActId, _targetX, _targetY, _isHit)); } else { if (_isHit) { if (getGfxId() > 0) { _npc.broadcastPacket(new S_UseAttackSkill(_target, _npcObjectId, getGfxId(), _targetX, _targetY, actId)); _target.broadcastPacketExceptTargetSight(new S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _npc); } else { _npc.broadcastPacket(new S_AttackPacketForNpc(_target, _npcObjectId, actId)); _target.broadcastPacketExceptTargetSight(new S_DoActionGFX(_targetId, ActionCodes.ACTION_Damage), _npc); } } else { if (getGfxId() > 0) { _npc.broadcastPacket(new S_UseAttackSkill(_target, _npcObjectId, getGfxId(), _targetX, _targetY, actId, 0)); } else { _npc.broadcastPacket(new S_AttackMissPacket(_npc, _targetId, actId)); } } } } /* * // 飛び道具(矢、スティング)がミスだったときの軌道を計算 public void calcOrbit(int cx, int cy, int * head) // 起点X 起点Y 今向いてる方向 { float dis_x = Math.abs(cx - _targetX); // * X方向のターゲットまでの距離 float dis_y = Math.abs(cy - _targetY); // Y方向のターゲットまでの距離 * float dis = Math.max(dis_x, dis_y); // ターゲットまでの距離 float avg_x = 0; float * avg_y = 0; if (dis == 0) { // 目標と同じ位置なら向いてる方向へ真っ直ぐ if (head == 1) { avg_x * = 1; avg_y = -1; } else if (head == 2) { avg_x = 1; avg_y = 0; } else if * (head == 3) { avg_x = 1; avg_y = 1; } else if (head == 4) { avg_x = 0; * avg_y = 1; } else if (head == 5) { avg_x = -1; avg_y = 1; } else if (head * == 6) { avg_x = -1; avg_y = 0; } else if (head == 7) { avg_x = -1; avg_y * = -1; } else if (head == 0) { avg_x = 0; avg_y = -1; } } else { avg_x = * dis_x / dis; avg_y = dis_y / dis; } * * int add_x = (int) Math.floor((avg_x 15) + 0.59f); // 上下左右がちょっと優先な丸め int * add_y = (int) Math.floor((avg_y 15) + 0.59f); // 上下左右がちょっと優先な丸め * * if (cx > _targetX) { add_x *= -1; } if (cy > _targetY) { add_y *= -1; } * * _targetX = _targetX + add_x; _targetY = _targetY + add_y; } */ /* ■■■■■■■■■■■■■■■ 計算結果反映 ■■■■■■■■■■■■■■■ */ public void commit() { if (_isHit) { if (_calcType == PC_PC || _calcType == NPC_PC) { commitPc(); } else if (_calcType == PC_NPC || _calcType == NPC_NPC) { commitNpc(); } } // ダメージ値及び命中率確認用メッセージ if (!Config.ALT_ATKMSG) { return; } if (Config.ALT_ATKMSG) { if ((_calcType == PC_PC || _calcType == PC_NPC) && !_pc.isGm()) { return; } if ((_calcType == PC_PC || _calcType == NPC_PC) && !_targetPc.isGm()) { return; } } String msg0 = ""; String msg1 = "に"; String msg2 = ""; String msg3 = ""; String msg4 = ""; if (_calcType == PC_PC || _calcType == PC_NPC) { // アタッカーがPCの場合 msg0 = _pc.getName(); } else if (_calcType == NPC_PC) { // アタッカーがNPCの場合 msg0 = _npc.getName(); } if (_calcType == NPC_PC || _calcType == PC_PC) { // ターゲットがPCの場合 msg4 = _targetPc.getName(); msg2 = "HitR" + _hitRate + "% THP" + _targetPc.getCurrentHp(); } else if (_calcType == PC_NPC) { // ターゲットがNPCの場合 msg4 = _targetNpc.getName(); msg2 = "Hit" + _hitRate + "% Hp" + _targetNpc.getCurrentHp(); } msg3 = _isHit ? _damage + "与えた" : "ミスしました"; if (_calcType == PC_PC || _calcType == PC_NPC) { // アタッカーがPCの場合 _pc.sendPackets(new S_ServerMessage(166, msg0, msg1, msg2, msg3, msg4)); // \f1%0が%4%1%3 // %2 } if (_calcType == NPC_PC || _calcType == PC_PC) { // ターゲットがPCの場合 _targetPc.sendPackets(new S_ServerMessage(166, msg0, msg1, msg2, msg3, msg4)); // \f1%0が%4%1%3 // %2 } } // ●●●● プレイヤーに計算結果を反映 ●●●● private void commitPc() { if (_calcType == PC_PC) { if (_drainMana > 0 && _targetPc.getCurrentMp() > 0) { if (_drainMana > _targetPc.getCurrentMp()) { _drainMana = _targetPc.getCurrentMp(); } short newMp = (short) (_targetPc.getCurrentMp() - _drainMana); _targetPc.setCurrentMp(newMp); newMp = (short) (_pc.getCurrentMp() + _drainMana); _pc.setCurrentMp(newMp); } if (_drainHp > 0) { // HP吸収による回復 short newHp = (short) (_pc.getCurrentHp() + _drainHp); _pc.setCurrentHp(newHp); } damagePcWeaponDurability(); // 武器を損傷させる。 _targetPc.receiveDamage(_pc, _damage, false); } else if (_calcType == NPC_PC) { _targetPc.receiveDamage(_npc, _damage, false); } } // ●●●● NPCに計算結果を反映 ●●●● private void commitNpc() { if (_calcType == PC_NPC) { if (_drainMana > 0) { int drainValue = _targetNpc.drainMana(_drainMana); int newMp = _pc.getCurrentMp() + drainValue; _pc.setCurrentMp(newMp); if (drainValue > 0) { int newMp2 = _targetNpc.getCurrentMp() - drainValue; _targetNpc.setCurrentMpDirect(newMp2); } } if (_drainHp > 0) { // HP吸収による回復 short newHp = (short) (_pc.getCurrentHp() + _drainHp); _pc.setCurrentHp(newHp); } damageNpcWeaponDurability(); // 武器を損傷させる。 _targetNpc.receiveDamage(_pc, _damage); } else if (_calcType == NPC_NPC) { _targetNpc.receiveDamage(_npc, _damage); } } /* ■■■■■■■■■■■■■■■ カウンターバリア ■■■■■■■■■■■■■■■ */ // ■■■■ カウンターバリア時の攻撃モーション送信 ■■■■ public void actionCounterBarrier() { if (_calcType == PC_PC) { _pc.setHeading(_pc.targetDirection(_targetX, _targetY)); // 向きのセット _pc.sendPackets(new S_AttackMissPacket(_pc, _targetId)); _pc.broadcastPacket(new S_AttackMissPacket(_pc, _targetId)); _pc.sendPackets(new S_DoActionGFX(_pc.getId(), ActionCodes.ACTION_Damage)); _pc.broadcastPacket(new S_DoActionGFX(_pc.getId(), ActionCodes.ACTION_Damage)); } else if (_calcType == NPC_PC) { int actId = 0; _npc.setHeading(_npc.targetDirection(_targetX, _targetY)); // 向きのセット if (getActId() > 0) { actId = getActId(); } else { actId = ActionCodes.ACTION_Attack; } if (getGfxId() > 0) { _npc.broadcastPacket(new S_UseAttackSkill(_target, _npc.getId(), getGfxId(), _targetX, _targetY, actId, 0)); } else { _npc.broadcastPacket(new S_AttackMissPacket(_npc, _targetId, actId)); } _npc.broadcastPacket(new S_DoActionGFX(_npc.getId(), ActionCodes.ACTION_Damage)); } } // ■■■■ 相手の攻撃に対してカウンターバリアが有効かを判別 ■■■■ public boolean isShortDistance() { boolean isShortDistance = true; if (_calcType == PC_PC) { if (_weaponType == 20 || _weaponType == 62 || _weaponType2 == 17) { // 弓、ガントレット、キーリンク isShortDistance = false; } } else if (_calcType == NPC_PC) { boolean isLongRange = (_npc.getLocation().getTileLineDistance(new Point(_targetX, _targetY)) > 1); int bowActId = _npc.getNpcTemplate().getBowActId(); // 距離が2以上、攻撃者の弓のアクションIDがある場合は遠攻撃 if (isLongRange && bowActId > 0) { isShortDistance = false; } } return isShortDistance; } // ■■■■ カウンターバリアのダメージを反映 ■■■■ public void commitCounterBarrier() { int damage = calcCounterBarrierDamage(); if (damage == 0) { return; } if (_calcType == PC_PC) { _pc.receiveDamage(_targetPc, damage, false); } else if (_calcType == NPC_PC) { _npc.receiveDamage(_targetPc, damage); } } // ●●●● カウンターバリアのダメージを算出 ●●●● private int calcCounterBarrierDamage() { int damage = 0; L1ItemInstance weapon = null; weapon = _targetPc.getWeapon(); if (weapon != null) { if (weapon.getItem().getType() == 3) { // 両手剣(BIG最大ダメージ+強化数+追加ダメージ)*2 damage = (weapon.getItem().getDmgLarge() + weapon.getEnchantLevel() + weapon.getItem().getDmgModifier()) * 2; } } return damage; } /* * 武器を損傷させる。 対NPCの場合、損傷確率は10%とする。祝福武器は3%とする。 */ private void damageNpcWeaponDurability() { int chance = 10; int bchance = 3; /* * 損傷しないNPC、素手、損傷しない武器使用、SOF中の場合何もしない。 */ if (_calcType != PC_NPC || _targetNpc.getNpcTemplate().is_hard() == false || _weaponType == 0 || weapon.getItem().get_canbedmg() == 0 || _pc.hasSkillEffect(SOUL_OF_FLAME)) { return; } // 通常の武器・呪われた武器 if ((_weaponBless == 1 || _weaponBless == 2) && ((_random.nextInt(100) + 1) < chance)) { // \f1あなたの%0が損傷しました。 _pc.sendPackets(new S_ServerMessage(268, weapon.getLogName())); _pc.getInventory().receiveDamage(weapon); } // 祝福された武器 if (_weaponBless == 0 && ((_random.nextInt(100) + 1) < bchance)) { // \f1あなたの%0が損傷しました。 _pc.sendPackets(new S_ServerMessage(268, weapon.getLogName())); _pc.getInventory().receiveDamage(weapon); } } /* * バウンスアタックにより武器を損傷させる。 バウンスアタックの損傷確率は10% */ private void damagePcWeaponDurability() { // PvP以外、素手、弓、ガントトレット、相手がバウンスアタック未使用、SOF中の場合何もしない if (_calcType != PC_PC || _weaponType == 0 || _weaponType == 20 || _weaponType == 62 || _targetPc.hasSkillEffect(BOUNCE_ATTACK) == false) {// || // _pc.hasSkillEffect(SOUL_OF_FLAME)) // { return; } /* * if (_random.nextInt(100) + 1 <= 10) { // \f1あなたの%0が損傷しました。 * _pc.sendPackets(new S_ServerMessage(268, weapon.getLogName())); * _pc.getInventory().receiveDamage(weapon); } */ // STR/3%の確率で攻撃上昇バフ if (_calcType == PC_PC) { if (_random.nextInt(100) + 1 <= (_targetPc.getStr() / 2) && !_targetPc.hasSkillEffect(L1SkillId.BOUNCE_ATTACK_ATKUP)) { S_EffectLocation packet = new S_EffectLocation(_targetPc.getX(), _targetPc.getY(), 7682); _targetPc.sendPackets(packet); _targetPc.broadcastPacket(packet); _targetPc.setSkillEffect(L1SkillId.BOUNCE_ATTACK_ATKUP, 3000); } } } }