#include "StdAfx.h"
#include "damagecalc.h"
#include "StatusScript.h"
#include "BaseObject.h"
#include "ObjectManager.h"
#include "Player.h"
#include "Monster.h"
#include "Skill_Common.h"
#include "SkillManager.h"
#include "SkillScript.h"
#include "MonsterScript.h"
#include "GameSrv.h"



cDamageCalc* cDamageCalc::mpDamageCalc = NULL;



cDamageCalc::cDamageCalc(void)
{
	/// 싱글톤 - 2번이상 객체를 생성 하려고 할경우 콘솔에 에러 찍어줌
	if( mpDamageCalc )
	{
		//CONSOLE->WriteLog( "mpDamageCalc new error");
	}
	else
	{
		mpDamageCalc = this;
	}
}



cDamageCalc::~cDamageCalc(void)
{
}



unsigned long cDamageCalc::PhyAttackSuccess100( unsigned long attackerStatusRate, unsigned char attackerLv,
									   long skillRate, unsigned long targetStatusAvoid, unsigned char targetLv )
{
	float num103 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 103 );
	float num104 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 104 );
	float num107 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 107 );
	float num108 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 108 );
	float num109 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 109 );

	long value;
	float valueA, valueB, valueC, valueD, valueE;

	/// [A] = ( [공격자] 캐릭터 스탯 명중 수치 + 아이템 명중 수치 ) * ((100 + 버프성 명중 수치[%]값) / 100) + 버프성 명중 수치[+-]값 )
	///	B =	( A * {num103} ) + [공격자] Lv * {num104} 
	///	C =	스킬 성공확률값
	///	[D] = ( [방어자] 캐릭터 스탯 회피 수치 + 아이템 회피 수치 ) * ((100 + 버프성 회피 수치[%]값) / 100) + 버프성 회피 수치[+-]값 )
	///	E =	( D * {num107} ) + [방어자] Lv * {num108}
	///	F =	{num109} + ( ( B + C ) - E )
	valueA = (float)attackerStatusRate;
	valueB = ( valueA * num103 ) + attackerLv * num104;
	valueC = (float)skillRate;
	valueD = (float)targetStatusAvoid;
	valueE = ( valueD * num107 ) + targetLv * num108;
	value = FloatToInt( num109 + ( ( valueB + valueC ) - valueE ) );

	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}



unsigned long cDamageCalc::MagAttackSuccess130( long skillRate, unsigned char attackerLv, unsigned char targetLv )
{

	float num131 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 131 );
	float num132 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 132 );

	long value;
	float valueA, valueB;

	/// [A] = 스킬 성공확률값
	///	B =	MIN(([공격자]Lv - [방어자]Lv) * {num131}, {num132})
	///	A + B
	valueA = (float)skillRate;
	valueB = ( attackerLv - targetLv ) * num131;
	if( valueB > num132 )
		valueB = num132;
	value = FloatToInt( valueA + valueB );

	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}


unsigned long cDamageCalc::PhyCritical200( unsigned long attackerStatusCri, long skillCri, unsigned char attackerLv, unsigned char targetLv )
{

	float num205 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 205 );
	float num206 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 206 );

	long value;
	float valueB, valueC, valueD;

	/// A =	[공격자] 캐릭터 스탯 물리 크리티컬 수치 + 아이템 물리 크리티컬 수치
	/// [B] = ( A * {num201} ) * (( {num202} + 버프성 물리 크리티컬 [%]값) / {num203} ) + ( 버프성 물리 크리티컬 수치[+-]값 * {num204} )
	/// C =	스킬 기본값
	/// D =	MIN((([공격자]Lv - [방어자]Lv) * {num206} ), {num205})
	/// E =	B + C + D

	valueB = (float)attackerStatusCri;
	valueC = (float)skillCri;
	valueD = (float)( ( attackerLv - targetLv ) * num206 );
	if( valueD > num205 )
		valueD = num205;
	value = FloatToInt( valueB + valueC + valueD );

	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}



unsigned long cDamageCalc::MagCritical230( unsigned long attackerStatusCri, long skillCri, unsigned char attackerLv, unsigned char targetLv )
{

	float num235 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 235 );
	float num236 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 236 );

	long value;
	float valueB, valueC, valueD;

	/// A =	[공격자] 캐릭터 스탯 마법 크리티컬 수치 + 아이템 마법 크리티컬 수치
	/// [B] = ( A * {num231} ) * (( {num232} + 버프성 마법 크리티컬 [%]값) / {num233} ) + ( 버프성 마법 크리티컬 수치[+-]값 * {num234} )
	/// C =	스킬 기본값
	/// D =	MIN((([공격자]Lv - [방어자]Lv) * {num236} ), {num235})
	/// E =	B + C + D
	valueB = (float)attackerStatusCri;
	valueC = (float)skillCri;
	valueD = (float)( (attackerLv - targetLv) * num236 );
	if( valueD > num235 )
		valueD = num235;
	value = FloatToInt( valueB + valueC + valueD );

	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}


unsigned long cDamageCalc::PhyDamage500( unsigned char attackerType, unsigned long attackerStatusPhyAttack, unsigned long targetStatusPhyDef, long skillAttackPlus,
								long skillAttackPer, unsigned char attackerLv, unsigned char targetLv )
{

	float num501 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 501 );
	float num502 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 502 );
	float num503 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 503 );
	float num504 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 504 );
	float num505 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 505 );
	//float num506 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 506 );
	//float num507 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 507 );
	float num508 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 508 );
	float num509 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 509 );
	float num510 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 510 );

	float value, valueA, valueB, valueC, valueD, valueE;

	// A =	[공격자] 물리 공격력		
	// B =	[방어자] 물리 방어력 / {num501}		
	// C =	[공격자] 스킬 공격력(+)		
	// D =	[공격자] 스킬 공격력(%) / {num502}		
	//캐릭터 [공격자] Lv < [방어자] Lv   E =  ( 100 - ((( [방어자] Lv - [공격자] Lv ) * {num503} ) ^ {num504} )) / 100	최소 {num505}
	//몬스터 [공격자] Lv < [방어자] Lv   E =  ( 100 - ((( [방어자] Lv - [공격자] Lv ) * {num506} ) ^ {num507} )) / 100	최소 {num505}
	//캐릭터몬스터 [공격자] Lv > [방어자] Lv   E =  1 + (( [공격자] Lv - [방어자] Lv ) / {num508} )	최대 {num509}
	// F =	((A * ({num510} + D)) + C ) - B) * E		

	valueA = (float)attackerStatusPhyAttack;
	valueB = (float)targetStatusPhyDef / num501;
	valueC = (float)skillAttackPlus;
	valueD = (float)skillAttackPer / num502;

	//if( attackerType == eOBJECTTYPE_MONSTER )
	//{
	//	num503 = num506;
	//	num504 = num507;
	//}

	if( attackerLv < targetLv )
	{
		if( attackerType == eOBJECTTYPE_MONSTER )
		{
			valueE = 1;
		}
		else
		{
			float powValue = pow( ( ( targetLv - attackerLv ) * num503 ) , num504 );
			valueE = ( 100.0f - powValue ) / 100;
			if( valueE < num505 )
				valueE = num505;
		}
	}
	else
	{
		valueE = 1 + ( (float)( attackerLv - targetLv ) / num508 );
		if( valueE > num509 )
			valueE = num509;
	}

	value = ( ( ( valueA * ( num510 + valueD ) ) + valueC ) - valueB ) * valueE;

	/// 데미지 값은 1보다 작을수 없다.
	return value > 1.0f ? FloatToInt( value ) : 1;
}



unsigned long cDamageCalc::MagDamage530( unsigned char attackerType, unsigned long attackerStatusMagAttack, unsigned long targetStatusMagDef, long skillAttackPlus,
								long skillAttackPer, unsigned char attackerLv, unsigned char targetLv )
{

	float num531 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 531 );
	float num532 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 532 );
	float num533 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 533 );
	float num534 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 534 );
	float num535 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 535 );
	//float num536 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 536 );
	//float num537 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 537 );
	float num538 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 538 );
	float num539 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 539 );
	float num540 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 540 );

	float value, valueA, valueB, valueC, valueD, valueE;

	// A =	[공격자] 마법 공격력		
	// B =	[방어자] 마법 방어력 / {num531}
	// C =	[공격자] 스킬 공격력(+)		
	// D =	[공격자] 스킬 공격력(%) / {num532}		
	//캐릭터 [공격자] Lv < [방어자] Lv   E =  ( 100 - ((( [방어자] Lv - [공격자] Lv ) * {num533} ) ^ {num534} )) / 100	최소 {num535}
	//몬스터 [공격자] Lv < [방어자] Lv   E =  ( 100 - ((( [방어자] Lv - [공격자] Lv ) * {num536} ) ^ {num537} )) / 100	최소 {num535}
	//캐릭터몬스터 [공격자] Lv > [방어자] Lv   E =  1 + (( [공격자] Lv - [방어자] Lv ) / {num538} )	최대 {num539}
	// F =	((A * ({num540} + D)) + C ) - B) * E

	valueA = (float)attackerStatusMagAttack;
	valueB = (float)targetStatusMagDef / num531;
	valueC = (float)skillAttackPlus;
	valueD = (float)skillAttackPer / num532;

	//if( attackerType == eOBJECTTYPE_MONSTER )
	//{
	//	num533 = num536;
	//	num534 = num537;
	//}

	if( attackerLv < targetLv )
	{
		if( attackerType == eOBJECTTYPE_MONSTER )
		{
			valueE = 1;
		}
		else
		{
			float powValue = pow( ( ( targetLv - attackerLv ) * num533 ) , num534 );
			valueE = ( 100.0f - powValue ) / 100;
			if( valueE < num535 )
				valueE = num535;
		}
	}
	else
	{
		valueE = 1 + ( (float)( attackerLv - targetLv ) / num538 );
		if( valueE > num539 )
			valueE = num539;
	}

	value = ( ( ( valueA * ( num540 + valueD ) ) + valueC ) - valueB ) * valueE;

	/// 데미지 값은 1보다 작을수 없다.
	return value > 1.0f ? FloatToInt( value ) : 1;
}



unsigned long cDamageCalc::PhyConditionOdd900( long skillRate, unsigned long attackerAttack, unsigned long targetDef,
                                      unsigned char attackerLv, unsigned char targetLv )
{

	float num901 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 901 );
	float num902 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 902 );
	float num903 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 903 );
	float num904 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 904 );
	float num905 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 905 );

	long value;
	float valueA, valueB, valueC;

	/// A =	스킬 성공 기본값
	///	B =	(([방어자] 물리 방어력 - [공격자] 물리 공격력 ) / [공격자] 물리 공격력) * {num901}		( 최소{num902}, 최대{num903} )
	///	C =	MIN(([공격자]Lv - [방어자]Lv) * {num904}, {num905})
	///	A - B + C
	valueA = (float)skillRate;
	valueB = ( ( (float)targetDef - attackerAttack ) / attackerAttack ) * num901;
	if( valueB < num902 )
		valueB = num902;
	if( valueB > num903 )
		valueB = num903;
	valueC = ( attackerLv - targetLv ) * num904;
	if( valueC > num905 )
		valueC = num905;
	value = FloatToInt( valueA - valueB + valueC );

	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}



unsigned long cDamageCalc::MagConditionOdd930( long skillRate, unsigned long attackerAttack, unsigned long targetDef,
                                              unsigned char attackerLv, unsigned char targetLv )
{

	float num931 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 931 );
	float num932 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 932 );
	float num933 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 933 );
	float num934 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 934 );
	float num935 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 935 );

	long value;
	float valueA, valueB, valueC;

	/// A =	스킬 성공 기본값
	///	B =	(([방어자] 마법 방어력 - [공격자] 마법 공격력 ) / [공격자] 마법 공격력) * {num931}		( 최소{num932}, 최대{num933} )
	///	C =	MIN(([공격자]Lv - [방어자]Lv) * {num934}, {num935})
	///	A - B + C
	valueA = (float)skillRate;
	valueB = ( ( (float)targetDef - attackerAttack ) / attackerAttack ) * num931;
	if( valueB < num932 )
		valueB = num932;
	if( valueB > num933 )
		valueB = num933;
	valueC = ( attackerLv - targetLv ) * num934;
	if( valueC > num935 )
		valueC = num935;
	value = FloatToInt( valueA - valueB + valueC );

	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}



unsigned long cDamageCalc::HealHP1200( long skillHeal, long statusPer, long statusHeal )
{

	float num1201 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1201 );
	float num1202 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1202 );

	long value;
	float valueA, valueB;

	/// A =	스킬 기본 회복량 * (( {num1201} + 버프성 회복량 [%]값) / {num1202} )
	///	[B] = ( 캐릭터 스탯 마법 공격력 * {num1203} ) + 아이템에 의한 스킬회복량 증가 수치 총합
	///	A + B
	valueA = skillHeal * ( ( num1201 + statusPer ) / num1202 );
	valueB = (float)statusHeal;
	value = FloatToInt( valueA + valueB );
    
	if( value < 0 )
		value = 0;

	/// 결과값 리턴
	return (unsigned long)value;
}


bool cDamageCalc::PlayerAttackSuccess( unsigned long playerIdx, sObject target, eATTRIBUTETYPE attributeType, long skillAccuracyValue )
{
	cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
	if( pPlayer == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::PlayerAttackSuccess pPlayer[%d] == NULL", playerIdx );
		return 0;
	}

	bool success = false;

	/// 타겟(몬스터)
	if( target.type == eOBJECTTYPE_MONSTER )
	{
		cMonster* pMonster = OBJECTMANAGER->GetMonster( target.index );
		if( pMonster == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::PlayerAttackSuccess pMonster[%d] == NULL", target.index );
			return 0;
		}
		success = SuccessCalcValue( pPlayer, pMonster, attributeType, skillAccuracyValue );
	}
	/// 타겟(플레이어)
	else if( target.type == eOBJECTTYPE_PLAYER )
	{
		cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index );
		if( pTargetPlayer == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::PlayerAttackSuccess pTargetPlayer[%d] == NULL", playerIdx );
			return 0;
		}
		success = SuccessCalcValue( pPlayer, pTargetPlayer, attributeType, skillAccuracyValue );
	}
	else
	{
		// 정의 안된 타겟
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::PlayerAttackSuccess target.type[%d]", target.type );
		return 0;
	}

	return success;

}


bool cDamageCalc::PlayerCritical( unsigned long playerIdx, sObject target, eATTRIBUTETYPE attributeType, short skillCriticalValue )
{
	cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
	if( pPlayer == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::PlayerCritical pPlayer[%d] == NULL", playerIdx );
		return 0;
	}

	bool cri = false;

	/// 타겟(몬스터)
	if( target.type == eOBJECTTYPE_MONSTER )
	{
		cMonster* pMonster = OBJECTMANAGER->GetMonster( target.index );
		if( pMonster == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::PlayerCritical pMonster[%d] == NULL", target.index );
			return 0;
		}
		cri = CriticalCalcValue( pPlayer, pMonster, attributeType, skillCriticalValue );
	}
	/// 타겟(플레이어)
	else if( target.type == eOBJECTTYPE_PLAYER )
	{
		cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index );
		if( pTargetPlayer == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::PlayerCritical pTargetPlayer[%d] == NULL", playerIdx );
			return 0;
		}
		cri = CriticalCalcValue( pPlayer, pTargetPlayer, attributeType, skillCriticalValue );
	}
	else
	{
		// 정의 안된 타겟
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::PlayerCritical target.type[%d]", target.type );
		return 0;
	}

	return cri;
}


unsigned long cDamageCalc::PlayerDamageCalc( unsigned long playerIdx, sObject target, eATTRIBUTETYPE attributeType, eRANGETYPE rangeType )
{
	cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( playerIdx );
	if( pPlayer == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::PlayerDamageCalc GetPlayer[%d]", playerIdx );
		return 0;
	}

	unsigned long damage = 0;

	/// 타겟(몬스터)
	if( target.type == eOBJECTTYPE_MONSTER )
	{
		cMonster* pMonster = OBJECTMANAGER->GetMonster( target.index );
		if( pMonster == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::PlayerDamageCalc GetMonster[%d]", target.index );
			return 0;
		}
		damage = DamageCalcValue( pPlayer, pMonster, attributeType, rangeType );
	}
	/// 타겟(플레이어)
	else if( target.type == eOBJECTTYPE_PLAYER )
	{
		cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index );
		if( pTargetPlayer == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::PlayerDamageCalc GetPlayer[%d]", playerIdx );
			return 0;
		}
		damage = DamageCalcValue( pPlayer, pTargetPlayer, attributeType, rangeType );
	}
	else
	{
		// 정의 안된 타겟
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::PlayerDamageCalc target.type[%d]", target.type );
		return 0;
	}

	return damage;
}


bool cDamageCalc::MonsterAttackSuccess( unsigned long monsterIdx, sObject target, eMONSTERATTACK_TYPE attackType, eATTRIBUTETYPE attributeType )
{
	cMonster* pMonster = OBJECTMANAGER->GetMonster( monsterIdx );
	if( pMonster == NULL )
	{
		assert(NULL);
		return 0;
	}

	bool success = false;

	/// 타겟(플레이어)
	if( target.type == eOBJECTTYPE_PLAYER )
	{
		cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index );
		if( pTargetPlayer == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::MonsterAttackSuccess pTargetPlayer[%d] == NULL", monsterIdx );
			return 0;
		}
		success = SuccessCalcValue( pMonster, pTargetPlayer, attackType, attributeType );
	}
	else
	{
		// 정의 안된 타겟
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::MonsterAttackSuccess target.type[%d]", target.type );
		return 0;
	}

	return success;

}


bool cDamageCalc::MonsterCritical( unsigned long monsterIdx, sObject target, eMONSTERATTACK_TYPE attackType, eATTRIBUTETYPE attributeType )
{
	cMonster* pMonster = OBJECTMANAGER->GetMonster( monsterIdx );
	if( pMonster == NULL )
	{
		assert(NULL);
		return 0;
	}

	bool cri = false;

	/// 타겟(플레이어)
	if( target.type == eOBJECTTYPE_PLAYER )
	{
		cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index );
		if( pTargetPlayer == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::MonsterCritical pTargetPlayer[%d] == NULL", monsterIdx );
			return 0;
		}
		cri = CriticalCalcValue( pMonster, pTargetPlayer, attackType, attributeType );
	}
	else
	{
		// 정의 안된 타겟
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::MonsterCritical target.type[%d]", target.type );
		return 0;
	}

	return cri;
}


unsigned long cDamageCalc::MonsterDamageCalc( unsigned long monsterIdx, sObject target, eMONSTERATTACK_TYPE attackType, eATTRIBUTETYPE attributeType, eRANGETYPE rangeType )
{
	cMonster* pMonster = OBJECTMANAGER->GetMonster( monsterIdx );
	if( pMonster == NULL )
	{
		assert(NULL);
		return 0;
	}

	unsigned long damage = 0;

	/// 타겟(플레이어)
	if( target.type == eOBJECTTYPE_PLAYER )
	{
		cPlayer* pTargetPlayer = OBJECTMANAGER->GetPlayer( target.index );
		if( pTargetPlayer == NULL )
		{
			assert(NULL);
			NETWORK2->PostServerEvent("cDamageCalc::MonsterDamageCalc GetPlayer[%d]", monsterIdx );
			return 0;
		}
		damage = DamageCalcValue( pMonster, pTargetPlayer, attackType, attributeType, rangeType );
	}
	else
	{
		// 정의 안된 타겟
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::MonsterDamageCalc target.type[%d]", target.type );
		return 0;
	}

	return damage;
}


unsigned long cDamageCalc::HealHPCalc( sObject attacker, long skillHeal )
{

	long statusPer = 0;
	long statusHeal = 0;

	unsigned long minHeal = 0;
	unsigned long maxHeal = 0;

	switch( attacker.type )
	{
	case eOBJECTTYPE_PLAYER:
		{
			cPlayer* pPlayer = OBJECTMANAGER->GetPlayer( attacker.index );
			if( pPlayer == NULL )
			{
				assert(NULL);
				NETWORK2->PostServerEvent("cDamageCalc::HealHPCalc GetPlayer[%d]", attacker.index );
				return 0;
			}

			statusPer = FloatToInt( pPlayer->GetStatus2Per( ePLAYER_STATUS_EXT_HEAL ) );

			minHeal = FloatToInt( pPlayer->GetStatus2()->mMinHeal );
			maxHeal = FloatToInt( pPlayer->GetStatus2()->mMaxHeal );
			statusHeal = minHeal;
			if( minHeal < maxHeal )
			{
				/// 회복수치를을 최대값에서 최소값 사이에 랜덤 값으로 설정
				statusHeal = maxHeal - minHeal;
				statusHeal = rand() % ( statusHeal + 1 );
				statusHeal = minHeal + statusHeal;
			}

			statusHeal = statusHeal + FloatToInt( pPlayer->GetStatus2Plus( ePLAYER_STATUS_EXT_HEAL ) );

		}
		break;
	}

	/// 회복(힐)
	return HealHP1200( skillHeal, statusPer, statusHeal );
}


unsigned long cDamageCalc::PlayerConditionOdd( sObject target, sObject attacker, long influenceRate, unsigned long skillClassIdx )
{
	cPlayer* pAttacker = OBJECTMANAGER->GetPlayer( attacker.index );
	if( pAttacker == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("PlayerConditionOdd pAttacker == NULL");
		return 0;
	}

	cBaseObject* pTarget = OBJECTMANAGER->GetObject( target.type, target.index );
	if( pTarget == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("PlayerConditionOdd pTarget == NULL");
		return 0;
	}

	bool isPhysical;		/// 물리/마법 
	bool isClose;			/// 근거리/원거리

	unsigned long attackerAttack, targetDef;	/// 공격자 공격력, 타겟 방어력
	unsigned char attackerLv, targetLv;			/// 공격자 레벨, 타겟 레벨
	unsigned long minAttack, maxAttack;			/// 최소 공격력, 최대 공격력

	attackerLv = pAttacker->GetLevel();

	/// 플레이어 스크립트 로드
	sPlayerSkillBaseInfo* pPlayerSkill = SKILLSCRIPT->GetPlayerSkillInfo( skillClassIdx );
	if( pPlayerSkill == NULL )
		return 0;

	/// 물리/마법 공격 확인
	isPhysical = pPlayerSkill->mAttributeType == eATTRIBUTETYPE_PHYSICAL;

	/// 물리
	if( isPhysical == true )
	{
		/// 근거리/원거리
		isClose =  pPlayerSkill->mRangeType == eRANGETYPE_CLOSE;

		if( isClose == true )
		{
			minAttack = (unsigned long)((cPlayer*)pAttacker)->GetStatus2()->mPhysicMinAttack;
			maxAttack = (unsigned long)((cPlayer*)pAttacker)->GetStatus2()->mPhysicMaxAttack;
		}
		else
		{
			minAttack = (unsigned long)((cPlayer*)pAttacker)->GetStatus2()->mPhysicMinRangeAttack;
			maxAttack = (unsigned long)((cPlayer*)pAttacker)->GetStatus2()->mPhysicMaxRangeAttack;
		}
	}
	else	/// 마법
	{
		minAttack = (unsigned long)((cPlayer*)pAttacker)->GetStatus2()->mMagicMinAttack;
		maxAttack = (unsigned long)((cPlayer*)pAttacker)->GetStatus2()->mMagicMaxAttack;
	}

	/// 공격력 산출
	attackerAttack = ( minAttack + maxAttack ) / 2;

	/// 타겟이 플레이어인 경우 방어력 산출
	if( pTarget->GetObjectType() == eOBJECTTYPE_PLAYER )
	{
		targetLv = ((cPlayer*)pTarget)->GetLevel();

		/// 물리
		if( isPhysical == true )
			targetDef = (unsigned long)((cPlayer*)pTarget)->GetStatus2()->mPhysicDefense;
		else	/// 마법
			targetDef = (unsigned long)((cPlayer*)pTarget)->GetStatus2()->mMagicDefense;

	}
	/// 몬스터인 경우
	else if( pTarget->GetObjectType() == eOBJECTTYPE_MONSTER )
	{

		sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( pTarget->GetRaceGender() );
		if( pMonsterScript == NULL )	return false;

		targetLv = pMonsterScript->mLevel;

		/// 물리
		if( isPhysical == true )
			targetDef = ((cMonster*)pTarget)->GetPhysicDefense();
		else	/// 마법
			targetDef = ((cMonster*)pTarget)->GetMagicDefense();

	}
	else
	{
		assert(NULL);
		NETWORK2->PostServerEvent("CheckInfluenceCreatePer ERR");
		return 0;
	}

	unsigned long checkPer = 0;

	if( isPhysical == true )
		checkPer = PhyConditionOdd900( influenceRate, attackerAttack, targetDef, attackerLv, targetLv );
	else
		checkPer = MagConditionOdd930( influenceRate, attackerAttack, targetDef, attackerLv, targetLv );

	return checkPer;
}


unsigned long cDamageCalc::MonsterConditionOdd( sObject target, sObject attacker, long influenceRate, unsigned long skillClassIdx )
{
	cMonster* pAttacker = OBJECTMANAGER->GetMonster( attacker.index );
	if( pAttacker == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("PlayerConditionOdd pAttacker == NULL");
		return 0;
	}

	cBaseObject* pTarget = OBJECTMANAGER->GetObject( target.type, target.index );
	if( pTarget == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("PlayerConditionOdd pTarget == NULL");
		return 0;
	}

	bool isPhysical;		/// 물리/마법 
	bool isClose;			/// 근거리/원거리

	unsigned long attackerAttack, targetDef;	/// 공격자 공격력, 타겟 방어력
	unsigned char attackerLv, targetLv;			/// 공격자 레벨, 타겟 레벨
	unsigned long minAttack, maxAttack;			/// 최소 공격력, 최대 공격력

	sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( pAttacker->GetRaceGender() );
	if( pMonsterScript == NULL )	
	{
		assert(NULL);
		NETWORK2->PostServerEvent("MonsterConditionOdd pMonsterScript[%d] == NULL", pAttacker->GetRaceGender() );
		return 0;
	}

	attackerLv = pMonsterScript->mLevel;

	/// 몬스터인 경우 몬스터 스크립트 로드
	sMonsterSkillScript* pMonsterSkill = (sMonsterSkillScript*)SKILLSCRIPT->GetMonsterSkillInfo( pAttacker->GetRaceGender(), (eMONSTERATTACK_TYPE)skillClassIdx );
	if( pMonsterSkill == NULL )
	{
		assert(NULL);
		NETWORK2->PostServerEvent("MonsterConditionOdd GetMonsterSkillInfo[%d] == NULL", skillClassIdx );
		return 0;
	}

	/// 물리/마법 공격 확인
	isPhysical = pMonsterSkill->mAttributeType == eATTRIBUTETYPE_PHYSICAL;

	/// 물리
	if( isPhysical == true )
	{
		/// 근거리/원거리
		isClose =  pMonsterSkill->mRangeType == eRANGETYPE_CLOSE;

		if( isClose == true )
		{
			minAttack = ((cMonster*)pAttacker)->CalcPhysicAttack( pMonsterSkill->mMinAttackValue );
			maxAttack = ((cMonster*)pAttacker)->CalcPhysicAttack( pMonsterSkill->mMaxAttackValue );
		}
		else
		{
			minAttack = ((cMonster*)pAttacker)->CalcPhysicRangeAttack( pMonsterSkill->mMinAttackValue );
			maxAttack = ((cMonster*)pAttacker)->CalcPhysicRangeAttack( pMonsterSkill->mMaxAttackValue );
		}
	}
	else	/// 마법
	{
		minAttack = ((cMonster*)pAttacker)->CalcMagicAttack( pMonsterSkill->mMinAttackValue );
		maxAttack = ((cMonster*)pAttacker)->CalcMagicAttack( pMonsterSkill->mMaxAttackValue );
	}

	attackerAttack = ( minAttack + maxAttack ) / 2;

	/// 타겟이 플레이어인 경우 방어력 산출
	if( pTarget->GetObjectType() == eOBJECTTYPE_PLAYER )
	{
		targetLv = ((cPlayer*)pTarget)->GetLevel();

		/// 물리
		if( isPhysical == true )
			targetDef = (unsigned long)((cPlayer*)pTarget)->GetStatus2()->mPhysicDefense;
		else	/// 마법
			targetDef = (unsigned long)((cPlayer*)pTarget)->GetStatus2()->mMagicDefense;

	}
	else if( pTarget->GetObjectType() == eOBJECTTYPE_MONSTER )
	{
		/// 몬스터가 몬스터에게 상태이상을 걸지 않는다.
		assert(NULL);
		NETWORK2->PostServerEvent("cDamageCalc::MonsterConditionOdd Monster To Monster" );

		sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( pTarget->GetRaceGender() );
		if( pMonsterScript == NULL )	return false;

		targetLv = pMonsterScript->mLevel;

		/// 물리
		if( isPhysical == true )
			targetDef = ((cMonster*)pTarget)->GetPhysicDefense();
		else	/// 마법
			targetDef = ((cMonster*)pTarget)->GetMagicDefense();

	}
	else
	{
		assert(NULL);
		NETWORK2->PostServerEvent("CheckInfluenceCreatePer ERR");
		return false;
	}

	unsigned long checkPer = 0;

	if( isPhysical == true )
		checkPer = PhyConditionOdd900( influenceRate, attackerAttack, targetDef, attackerLv, targetLv );
	else
		checkPer = MagConditionOdd930( influenceRate, attackerAttack, targetDef, attackerLv, targetLv );

	return checkPer;
}


bool cDamageCalc::SuccessCalcValue( cPlayer* pAttacker, cMonster* pTarget, eATTRIBUTETYPE attributeType, long skillRate )
{
	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long attackerStatusRate = FloatToInt( pAttacker->GetStatus2()->mPhysicAttackRate );
	unsigned long targetStatusAvoid = pTarget->GetAvoid();

	unsigned long attackSuccessPer = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
	{
		attackSuccessPer = PhyAttackSuccess100( attackerStatusRate, attackerLv, skillRate, targetStatusAvoid, targetLv );
	}
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
	{
		attackSuccessPer = MagAttackSuccess130( skillRate, attackerLv, targetLv );
	}

	/// 공격 랜덤 체크
	unsigned long randvalue = (unsigned long)(RANDOMTABLE->Get( ) * 100);
	if( randvalue > attackSuccessPer ) 
		return false;

	return true;

}


bool cDamageCalc::CriticalCalcValue( cPlayer* pAttacker, cMonster* pTarget, eATTRIBUTETYPE attributeType, long skillCri )
{
	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long attackerStatusCri = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		attackerStatusCri = FloatToInt( pAttacker->GetStatus2()->mPhysicCritical );
	else if(  attributeType == eATTRIBUTETYPE_MAGIC )
		attackerStatusCri = FloatToInt( pAttacker->GetStatus2()->mMagicCritical );
	else
		assert(NULL);

	/// 크리티컬 발생 확율
	unsigned long criticalPer = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		criticalPer = PhyCritical200( attackerStatusCri, skillCri, attackerLv, targetLv );
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		criticalPer = MagCritical230( attackerStatusCri, skillCri, attackerLv, targetLv );

	unsigned long randvalue = rand() % 100;
	if( randvalue > criticalPer ) 
		return false;

	return true;

}


unsigned long cDamageCalc::DamageCalcValue( cPlayer* pAttacker, cMonster* pTarget, eATTRIBUTETYPE attributeType, eRANGETYPE rangeType )
{
	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long minAttack = 0;
	unsigned long maxAttack = 0;

	unsigned long targetStatusDef = 0;
	unsigned long skillAttackPlus = 0;
	unsigned long skillAttackPer = 0;
	unsigned long attackerStatusAttack = 0;

	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
	{
		if( rangeType == eRANGETYPE_CLOSE )
		{
			minAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMinAttack );
			maxAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMaxAttack );
		}
		else if( rangeType == eRANGETYPE_LONG )
		{
			minAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMinRangeAttack );
			maxAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMaxRangeAttack );
		}
		else
			assert(NULL);

		attackerStatusAttack = minAttack;
		if( minAttack < maxAttack )
		{
			/// 물리 공격력을 최대값에서 최소값 사이에 랜덤 값으로 설정
			attackerStatusAttack = maxAttack - minAttack;
			attackerStatusAttack = rand() % ( attackerStatusAttack + 1 );
			attackerStatusAttack = minAttack + attackerStatusAttack;
		}

		///// 랜덤 제거 공격력
		//attackerStatusAttack = ( minAttack + maxAttack ) / 2;

		/// 방어력 DEFENSE_RANDOM_PER 값만큼 랜덤 선택
		targetStatusDef = pTarget->GetPhysicDefense() * 
			( DEFENSE_RANDOM_PER + ( rand() % ( 100 -  DEFENSE_RANDOM_PER + 1 ) ) ) / 100;

		///// 랜덤 제거 방어력
		//targetStatusDef = pTarget->GetPhysicDefense();

		skillAttackPlus = pAttacker->GetDamagecalc()->mPhyInstantPlusAttack;
		skillAttackPer = pAttacker->GetDamagecalc()->mPhyInstantPerAttack;
	}
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
	{
		minAttack = FloatToInt( pAttacker->GetStatus2()->mMagicMinAttack );
		maxAttack = FloatToInt( pAttacker->GetStatus2()->mMagicMaxAttack );
		attackerStatusAttack = minAttack;
		if( minAttack < maxAttack )
		{
			/// 마법 공격력을 최대값에서 최소값 사이에 랜덤 값으로 설정
			attackerStatusAttack = maxAttack - minAttack;
			attackerStatusAttack = rand() % ( attackerStatusAttack + 1 );
			attackerStatusAttack = minAttack + attackerStatusAttack;
		}

		///// 랜덤 제거 공격력
		//attackerStatusAttack = ( minAttack + maxAttack ) / 2;

		/// 방어력 DEFENSE_RANDOM_PER 값만큼 랜덤 선택
		targetStatusDef = pTarget->GetMagicDefense() * 
			( DEFENSE_RANDOM_PER + ( rand() % ( 100 -  DEFENSE_RANDOM_PER + 1 ) ) ) / 100;

		///// 랜덤 제거 방어력
		//targetStatusDef = pTarget->GetMagicDefense();

		skillAttackPlus = pAttacker->GetDamagecalc()->mMagicInstantPlusAttack;
		skillAttackPer = pAttacker->GetDamagecalc()->mMagicInstantPerAttack;
	}
	else
		assert(NULL);


	unsigned long damage = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		damage = PhyDamage500( pAttacker->GetObjectType(), attackerStatusAttack, targetStatusDef, skillAttackPlus,
		skillAttackPer, attackerLv, targetLv );

	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		damage = MagDamage530( pAttacker->GetObjectType(), attackerStatusAttack, targetStatusDef, skillAttackPlus,
		skillAttackPer, attackerLv, targetLv );

	return damage;
}


bool cDamageCalc::SuccessCalcValue( cMonster* pAttacker, cPlayer* pTarget, eMONSTERATTACK_TYPE attackType, eATTRIBUTETYPE attributeType )
{
	sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( pAttacker->GetRaceGender() );
	sMonsterSkillScript* pMonsterSkill = SKILLSCRIPT->GetMonsterSkillInfo( pAttacker->GetRaceGender(), attackType );
	if( pMonsterScript == NULL || pMonsterSkill == NULL )
	{
		assert(NULL);
		return 0;
	}

	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long attackerStatusRate = 0;	/// 몬스터는 기본 스텟 수치가 없다.
	unsigned long targetStatusAvoid = FloatToInt( pTarget->GetStatus2()->mAvoid );
	unsigned long skillRate = pAttacker->CalcPhysicAttackRate( pMonsterSkill->mAccuracyValue );

	unsigned long attackSuccessPer = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
	{
		attackSuccessPer = PhyAttackSuccess100( attackerStatusRate, attackerLv, skillRate, targetStatusAvoid, targetLv );
	}
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
	{
		attackSuccessPer = MagAttackSuccess130( skillRate, attackerLv, targetLv );
	}

	/// 공격 랜덤 체크
	unsigned long randvalue = (unsigned long)(RANDOMTABLE->Get( ) * 100);
	if( randvalue > attackSuccessPer ) 
		return false;

	return true;

}


bool cDamageCalc::CriticalCalcValue( cMonster* pAttacker, cPlayer* pTarget, eMONSTERATTACK_TYPE attackType, eATTRIBUTETYPE attributeType )
{
	sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( pAttacker->GetRaceGender() );
	sMonsterSkillScript* pMonsterSkill = SKILLSCRIPT->GetMonsterSkillInfo( pAttacker->GetRaceGender(), attackType );
	if( pMonsterScript == NULL || pMonsterSkill == NULL )
	{
		assert(NULL);
		return 0;
	}

	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long attackerStatusCri = 0;	/// 몬스터는 기본 스텟 수치가 없다.
	unsigned long skillCri = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		skillCri = pAttacker->CalcPhysicCritical( pMonsterSkill->mCriticalValue );
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		skillCri = pAttacker->CalcMagicCritical( pMonsterSkill->mCriticalValue );
	else
		assert(NULL);

	/// 크리티컬 발생 확율
	unsigned long criticalPer = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		criticalPer = PhyCritical200( attackerStatusCri, skillCri, attackerLv, targetLv );
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		criticalPer = MagCritical230( attackerStatusCri, skillCri, attackerLv, targetLv );

	unsigned long randvalue = rand() % 100;
	if( randvalue > criticalPer ) 
		return false;

	return true;

}


unsigned long cDamageCalc::DamageCalcValue( cMonster* pAttacker, cPlayer* pTarget, eMONSTERATTACK_TYPE attackType, eATTRIBUTETYPE attributeType, eRANGETYPE rangeType )
{
	sMonsterScript* pMonsterScript = MONSTERSCRIPT->GetMonsterListInfo( pAttacker->GetRaceGender() );
	sMonsterSkillScript* pMonsterSkill = SKILLSCRIPT->GetMonsterSkillInfo( pAttacker->GetRaceGender(), attackType );
	if( pMonsterScript == NULL || pMonsterSkill == NULL )
	{
		assert(NULL);
		return 0;
	}

	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long minAttack = 0;
	unsigned long maxAttack = 0;

	unsigned long targetStatusDef = 0;
	unsigned long skillAttackPlus = 0;
	unsigned long skillAttackPer = 0;
	unsigned long attackerStatusAttack = 0;

	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
	{
		if( rangeType == eRANGETYPE_CLOSE )
		{
			minAttack = pAttacker->CalcPhysicAttack( pMonsterSkill->mMinAttackValue );
			maxAttack = pAttacker->CalcPhysicAttack( pMonsterSkill->mMaxAttackValue );
		}
		else if( rangeType == eRANGETYPE_LONG )
		{
			minAttack = pAttacker->CalcPhysicRangeAttack( pMonsterSkill->mMinAttackValue );
			maxAttack = pAttacker->CalcPhysicRangeAttack( pMonsterSkill->mMaxAttackValue );
		}
		else
			assert(NULL);

		attackerStatusAttack = minAttack;
		if( minAttack < maxAttack )
		{
			/// 물리 공격력을 최대값에서 최소값 사이에 랜덤 값으로 설정
			attackerStatusAttack = maxAttack - minAttack;
			attackerStatusAttack = rand() % ( attackerStatusAttack + 1 );
			attackerStatusAttack = minAttack + attackerStatusAttack;
		}

		///// 랜덤 제거 공격력
		//attackerStatusAttack = ( minAttack + maxAttack ) / 2;

		/// 방어력 DEFENSE_RANDOM_PER 값만큼 랜덤 선택
		targetStatusDef = FloatToInt( pTarget->GetStatus2()->mPhysicDefense * 
			( DEFENSE_RANDOM_PER + ( rand() % ( 100 -  DEFENSE_RANDOM_PER + 1 ) ) ) / 100 );

		///// 랜덤 제거 방어력
		//targetStatusDef = FloatToInt( pTarget->GetStatus2()->mPhysicDefense );
	}
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
	{
		minAttack = pAttacker->CalcMagicAttack( pMonsterSkill->mMinAttackValue );
		maxAttack = pAttacker->CalcMagicAttack( pMonsterSkill->mMaxAttackValue );
		attackerStatusAttack = minAttack;
		if( minAttack < maxAttack )
		{
			/// 마법 공격력을 최대값에서 최소값 사이에 랜덤 값으로 설정
			attackerStatusAttack = maxAttack - minAttack;
			attackerStatusAttack = rand() % ( attackerStatusAttack + 1 );
			attackerStatusAttack = minAttack + attackerStatusAttack;
		}

		///// 랜덤 제거 공격력
		//attackerStatusAttack = ( minAttack + maxAttack ) / 2;

		/// 방어력 DEFENSE_RANDOM_PER 값만큼 랜덤 선택
		targetStatusDef = FloatToInt( pTarget->GetStatus2()->mMagicDefense * 
			( DEFENSE_RANDOM_PER + ( rand() % ( 100 -  DEFENSE_RANDOM_PER + 1 ) ) ) / 100 );

		///// 랜덤 제거 방어력
		//targetStatusDef = FloatToInt( pTarget->GetStatus2()->mMagicDefense );
	}
	else
		assert(NULL);


	unsigned long damage = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		damage = PhyDamage500( pAttacker->GetObjectType(), attackerStatusAttack, targetStatusDef, skillAttackPlus,
		skillAttackPer, attackerLv, targetLv );

	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		damage = MagDamage530( pAttacker->GetObjectType(), attackerStatusAttack, targetStatusDef, skillAttackPlus,
		skillAttackPer, attackerLv, targetLv );

	return damage;
}


bool cDamageCalc::SuccessCalcValue( cPlayer* pAttacker, cPlayer* pTarget, eATTRIBUTETYPE attributeType, long skillRate )
{
	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long attackerStatusRate = FloatToInt( pAttacker->GetStatus2()->mPhysicAttackRate );
	unsigned long targetStatusAvoid = FloatToInt( pTarget->GetStatus2()->mAvoid );

	unsigned long attackSuccessPer = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
	{
		attackSuccessPer = PhyAttackSuccess100( attackerStatusRate, attackerLv, skillRate, targetStatusAvoid, targetLv );
	}
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
	{
		attackSuccessPer = MagAttackSuccess130( skillRate, attackerLv, targetLv );
	}

	/// 공격 랜덤 체크
	unsigned long randvalue = (unsigned long)(RANDOMTABLE->Get( ) * 100);
	if( randvalue > attackSuccessPer ) 
		return false;

	return true;

}


bool cDamageCalc::CriticalCalcValue( cPlayer* pAttacker, cPlayer* pTarget, eATTRIBUTETYPE attributeType, long skillCri )
{
	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long attackerStatusCri = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		attackerStatusCri = FloatToInt( pAttacker->GetStatus2()->mPhysicCritical );
	else if(  attributeType == eATTRIBUTETYPE_MAGIC )
		attackerStatusCri = FloatToInt( pAttacker->GetStatus2()->mMagicCritical );
	else
		assert(NULL);

	/// 크리티컬 발생 확율
	unsigned long criticalPer = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		criticalPer = PhyCritical200( attackerStatusCri, skillCri, attackerLv, targetLv );
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		criticalPer = MagCritical230( attackerStatusCri, skillCri, attackerLv, targetLv );

	unsigned long randvalue = rand() % 100;
	if( randvalue > criticalPer ) 
		return false;

	return true;

}


unsigned long cDamageCalc::DamageCalcValue( cPlayer* pAttacker, cPlayer* pTarget, eATTRIBUTETYPE attributeType, eRANGETYPE rangeType )
{
	unsigned char attackerLv = pAttacker->GetLevel();
	unsigned char targetLv = pTarget->GetLevel();

	unsigned long minAttack = 0;
	unsigned long maxAttack = 0;

	unsigned long targetStatusDef = 0;
	unsigned long skillAttackPlus = 0;
	unsigned long skillAttackPer = 0;
	unsigned long attackerStatusAttack = 0;

	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
	{
		if( rangeType == eRANGETYPE_CLOSE )
		{
			minAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMinAttack );
			maxAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMaxAttack );
		}
		else if( rangeType == eRANGETYPE_LONG )
		{
			minAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMinRangeAttack );
			maxAttack = FloatToInt( pAttacker->GetStatus2()->mPhysicMaxRangeAttack );
		}
		else
			assert(NULL);

		attackerStatusAttack = minAttack;
		if( minAttack < maxAttack )
		{
			/// 물리 공격력을 최대값에서 최소값 사이에 랜덤 값으로 설정
			attackerStatusAttack = maxAttack - minAttack;
			attackerStatusAttack = rand() % ( attackerStatusAttack + 1 );
			attackerStatusAttack = minAttack + attackerStatusAttack;
		}

		///// 랜덤 제거 공격력
		//attackerStatusAttack = ( minAttack + maxAttack ) / 2;

		/// 방어력 DEFENSE_RANDOM_PER 값만큼 랜덤 선택
		targetStatusDef = FloatToInt( pTarget->GetStatus2()->mPhysicDefense * 
			( DEFENSE_RANDOM_PER + ( rand() % ( 100 -  DEFENSE_RANDOM_PER + 1 ) ) ) / 100 );

		///// 랜덤 제거 방어력
		//targetStatusDef = FloatToInt( pTarget->GetStatus2()->mPhysicDefense );

		skillAttackPlus = pAttacker->GetDamagecalc()->mPhyInstantPlusAttack;
		skillAttackPer = pAttacker->GetDamagecalc()->mPhyInstantPerAttack;
	}
	else if( attributeType == eATTRIBUTETYPE_MAGIC )
	{
		minAttack = FloatToInt( pAttacker->GetStatus2()->mMagicMinAttack );
		maxAttack = FloatToInt( pAttacker->GetStatus2()->mMagicMaxAttack );
		attackerStatusAttack = minAttack;
		if( minAttack < maxAttack )
		{
			/// 마법 공격력을 최대값에서 최소값 사이에 랜덤 값으로 설정
			attackerStatusAttack = maxAttack - minAttack;
			attackerStatusAttack = rand() % ( attackerStatusAttack + 1 );
			attackerStatusAttack = minAttack + attackerStatusAttack;
		}

		///// 랜덤 제거 공격력
		//attackerStatusAttack = ( minAttack + maxAttack ) / 2;

		/// 방어력 DEFENSE_RANDOM_PER 값만큼 랜덤 선택
		targetStatusDef = FloatToInt(  pTarget->GetStatus2()->mMagicDefense * 
			( DEFENSE_RANDOM_PER + ( rand() % ( 100 -  DEFENSE_RANDOM_PER + 1 ) ) ) / 100 );

		///// 랜덤 제거 방어력
		//targetStatusDef = FloatToInt( pTarget->GetStatus2()->mMagicDefense );

		skillAttackPlus = pAttacker->GetDamagecalc()->mMagicInstantPlusAttack;
		skillAttackPer = pAttacker->GetDamagecalc()->mMagicInstantPerAttack;
	}
	else
		assert(NULL);


	unsigned long damage = 0;
	if( attributeType == eATTRIBUTETYPE_PHYSICAL )
		damage = PhyDamage500( pAttacker->GetObjectType(), attackerStatusAttack, targetStatusDef, skillAttackPlus,
		skillAttackPer, attackerLv, targetLv );

	else if( attributeType == eATTRIBUTETYPE_MAGIC )
		damage = MagDamage530( pAttacker->GetObjectType(), attackerStatusAttack, targetStatusDef, skillAttackPlus,
		skillAttackPer, attackerLv, targetLv );

	return damage;
}


