L1J-JP2 WarServerV2 - L1Attack
/*
 * 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);
			}
		}

	}
}