#include "stdafx.h"
#include "ObjectManager.h"
#include "StatusCalc_Client.h"
#include "Hero.h"
#include "GameResourceManager.h"
#include "SkillScript.h"
#include "StatusScript.h"
#include "SkillManager.h"
#include "Skill_Common.h"
#include "item_Common.h"
#include "ItemManager.h"


cStatusCalc_Client* cStatusCalc_Client::mpStatusCalc = NULL;


cStatusCalc_Client::cStatusCalc_Client(void)
{
	if( !mpStatusCalc )
	{
		mpStatusCalc = this;
	}
}



cStatusCalc_Client::~cStatusCalc_Client(void)
{
}



void cStatusCalc_Client::CalcPlayerStatusItemSkillAddDetail( eSTATUS_PLUS statusType, float value, bool color )
{
	unsigned long arrayNum = 0;

	if( eSTATUSPLUS_STR_PLUS <= statusType && statusType < eSTATUSPLUS_BASE_MAX )
	{
		arrayNum = statusType - eSTATUSPLUS_STR_PLUS;
		mBaseStatusPlus[arrayNum] = mBaseStatusPlus[arrayNum] + value;
		/// 항목별 색값을 지정한다. 
		if( color == true )		/// 패시브는 색변환 안함
			SetBaseStatusInfoType( (ePLAYER_STATUS)arrayNum, value, mBaseStatusPlus[arrayNum] );
	}

	else if( eSTATUSPLUS_ATK_PLUS <= statusType && statusType < eSTATUSPLUS_SKILL_HP_PLUS_PLUS )
	{
		arrayNum = statusType - eSTATUSPLUS_ATK_PLUS;
		mExtStatusPlus[arrayNum] = mExtStatusPlus[arrayNum] + value;
		if( color == true )
			SetExtStatusInfoType( (ePLAYER_STATUS_EXT)arrayNum, value, mExtStatusPlus[arrayNum] );
	}

	/// 공격력 전체를 변경+
	else if( eSTATUSPLUS_ATKTOTAL_PLUS == statusType )
	{
		mExtStatusPlus[ePLAYER_STATUS_EXT_ATK] += value;
		mExtStatusPlus[ePLAYER_STATUS_EXT_RATK] += value;
		mExtStatusPlus[ePLAYER_STATUS_EXT_MATK] += value;			
		if( color == true )
		{
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_ATK, value, mExtStatusPlus[ePLAYER_STATUS_EXT_ATK] );
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_RATK, value, mExtStatusPlus[ePLAYER_STATUS_EXT_RATK] );
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_MATK, value, mExtStatusPlus[ePLAYER_STATUS_EXT_MATK] );
		}
	}

	/// 방어력 전체를 변경+
	else if( eSTATUSPLUS_DEFTOTAL_PLUS == statusType )
	{
		mExtStatusPlus[ePLAYER_STATUS_EXT_DEF] += value;
		mExtStatusPlus[ePLAYER_STATUS_EXT_MDEF] += value;
		if( color == true )
		{
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_DEF, value, mExtStatusPlus[ePLAYER_STATUS_EXT_DEF] );
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_MDEF, value, mExtStatusPlus[ePLAYER_STATUS_EXT_MDEF] );
		}
	}

	else if( eSTATUSPLUS_ATK_PER <= statusType && statusType <= eSTATUSPLUS_SKILL_HP_PLUS_PER )
	{

		arrayNum = statusType - eSTATUSPLUS_ATK_PER;
		mExtStatusPer[arrayNum] = mExtStatusPer[arrayNum] + value;
		/// 패시브는 색변환 안함
		if( color == true )
		{
			/// 항목별 색값을 지정한다. 
			SetExtStatusInfoType( (ePLAYER_STATUS_EXT)arrayNum, value, mExtStatusPer[arrayNum] );
		}

	}

	/// 공격력 전체를 변경%
	else if( eSTATUSPLUS_ATKTOTAL_PER == statusType )
	{
		mExtStatusPer[ePLAYER_STATUS_EXT_ATK] += value;
		mExtStatusPer[ePLAYER_STATUS_EXT_RATK] += value;
		mExtStatusPer[ePLAYER_STATUS_EXT_MATK] += value;			
		if( color == true )
		{
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_ATK, value, mExtStatusPer[ePLAYER_STATUS_EXT_ATK] );
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_RATK, value, mExtStatusPer[ePLAYER_STATUS_EXT_RATK] );
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_MATK, value, mExtStatusPer[ePLAYER_STATUS_EXT_MATK] );
		}
	}

	/// 방어력 전체를 변경%
	else if( eSTATUSPLUS_DEFTOTAL_PER == statusType )
	{
		mExtStatusPer[ePLAYER_STATUS_EXT_DEF] += value;
		mExtStatusPer[ePLAYER_STATUS_EXT_MDEF] += value;
		if( color == true )
		{
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_DEF, value, mExtStatusPer[ePLAYER_STATUS_EXT_DEF] );
			SetExtStatusInfoType( ePLAYER_STATUS_EXT_MDEF, value, mExtStatusPer[ePLAYER_STATUS_EXT_MDEF] );
		}
	}

	else if( eSTATUSPLUS_EXPADDPER <= statusType && statusType < eSTATUSPLUS_BUFF_ETC_MAX )
	{
		arrayNum = statusType - eSTATUSPLUS_EXPADDPER;
		mExtAddStatus[arrayNum] = mExtAddStatus[arrayNum] + value;
	}

}



void cStatusCalc_Client::SetBaseStatusInfoType( ePLAYER_STATUS pos, float value, float totalValue )
{

	if( !( ePLAYER_STATUS_STR <= pos && pos < ePLAYER_STATUS_LEVEL ) )
	{
		assert(NULL);
		return;
	}

	/// 플레이어 정보 읽어옴
	cHero* pHero = OBJECTMANAGER->GetHero();

	/// 현재 컬러 타입을 가져옴
	eStateInfo_Type colorType;
	colorType = pHero->GetBaseStatusInfoType( pos );

	/// 읽어온 수치값이 0 일경우 리턴
	if( value == 0 ) { return; }

	/// 기존 컬러타입이 없는 상태에 +값이 들어 온경우
	else if( colorType == eSTATE_NORMAL && value > 0 )
	{
		/// 컬러타입을 +색으로 설정
		pHero->SetBaseStatusInfoType( pos, eSTATE_PLUS );
	}
	/// 기존 컬러타입이 없는 상태에 -값이 들어 온경우
	else if( colorType == eSTATE_NORMAL && value < 0 )
	{
		/// 컬러타입을 -색으로 설정
		pHero->SetBaseStatusInfoType( pos, eSTATE_MINUS );
	}
	/// 기존 컬러타입이 +상태에서 -값이 들어 온경우 또는 기존 컬러타입이 -상태에서 +값이 들어 온경우
	else if( ( colorType == eSTATE_PLUS && value < 0 ) || ( colorType == eSTATE_MINUS && value > 0 ))
	{
		if( totalValue > 0 )
		{
			/// 컬러타입을 +색으로 설정
			pHero->SetBaseStatusInfoType( pos, eSTATE_OVERLAPPLUS );
		}
		else
		{
			/// 컬러타입을 +색으로 설정
			pHero->SetBaseStatusInfoType( pos, eSTATE_OVERLAPMINUS );
		}
	}
}



void cStatusCalc_Client::SetExtStatusInfoType( ePLAYER_STATUS_EXT pos, float value, float totalValue )
{

	if( !( ePLAYER_STATUS_EXT_ATK <= pos && pos <= ePLAYER_STATUS_EXT_MAX ) )
	{
		assert(NULL);
		return;
	}

	/// 현재 컬러 타입을 가져옴
	eStateInfo_Type colorType;
	colorType = HERO->GetExtStatusInfoType( pos );

	/// 읽어온 수치값이 0 일경우 리턴
	if( value == 0 ) { return; }

	/// 기존 컬러타입이 없는 상태에 +값이 들어 온경우
	else if( colorType == eSTATE_NORMAL && value > 0 )
	{
		/// 컬러타입을 +색으로 설정
		HERO->SetExtStatusInfoType( pos, eSTATE_PLUS );
	}
	/// 기존 컬러타입이 없는 상태에 -값이 들어 온경우
	else if( colorType == eSTATE_NORMAL && value < 0 )
	{
		/// 컬러타입을 -색으로 설정
		HERO->SetExtStatusInfoType( pos, eSTATE_MINUS );
	}
	/// 기존 컬러타입이 +상태에서 -값이 들어 온경우 또는 기존 컬러타입이 -상태에서 +값이 들어 온경우
	else if( ( colorType == eSTATE_PLUS && value < 0 ) || ( colorType == eSTATE_MINUS && value > 0 ))
	{
		if( totalValue > 0 )
		{
			/// 컬러타입을 +색으로 설정
			HERO->SetExtStatusInfoType( pos, eSTATE_OVERLAPPLUS );
		}
		else
		{
			/// 컬러타입을 +색으로 설정
			HERO->SetExtStatusInfoType( pos, eSTATE_OVERLAPMINUS );
		}
	}
}


void cStatusCalc_Client::CalcPlayerBaseOnly()
{
	//HERO->InitStatusColor();

	/// 기본 스텟 초기화
	for( unsigned char i = ePLAYER_STATUS_STR ; ePLAYER_STATUS_LEVEL > i ; ++i )
	{
		mBaseStatus[i] = 0.0f;
	}

	/// 스크립트에서 읽어들인 순수한 기본 스텟값 계산
	CalcPlayerStatus();
}



void cStatusCalc_Client::CalcPlayerExtensionOnly()
{
	HERO->InitStatusInfoType();

	/// 스텟1 + 초기화
	for( unsigned char i = ePLAYER_STATUS_STR ; ePLAYER_STATUS_LEVEL > i ; ++i )
	{
		mBaseStatusPlus[i] = 0.0f;
	}

	/// 스텟2 + 초기화
	for( int i = ePLAYER_STATUS_EXT_ATK ; ePLAYER_STATUS_EXT_MAX > i ; ++i )
	{
		mExtStatusPlus[i] = 0;
	}

	/// 스텟2 % 초기화
	for( int i = ePLAYER_STATUS_EXT_ATK ; ePLAYER_STATUS_EXT_MAX > i ; ++i )
	{
		mExtStatusPer[i] = 0;
	}

	/// 스텟외 스텟
	for( int i = ePLAYER_STATUS_EXT_ADD_EXPADDPER ; ePLAYER_STATUS_EXT_ADD_MAX > i ; ++i )
	{
		mExtAddStatus[i] = 0;
	}

	/// 스킬효과, 스킬패시브, 아이템 데이타를 읽어와 스텟 수치 적용
	CalcPlayerStatusSkillInfluenceAdd();
	CalcPlayerStatusSkillPassiveAdd();
	CalcPlayerStatusItemAdd();
}



unsigned long cStatusCalc_Client::GetParantJob( unsigned long job, unsigned int jobPos )
{

	unsigned long jobCode;

	/// 현재 직업의 부모 직업들을 배열로 받아온다.
	tArray<unsigned long>* pParentJob;

	/// 상위 직업 코드를 읽어옮
	pParentJob = GAMERESOURCEMAN->GetParentJob( job );

	/// 데이터가 없다 - 현재 직업이 기본 직업 이다.
	if( pParentJob == NULL )
	{
		return NULL;
	}

	/// 사이즈보다 크다 - 현재 직업이 최종 직업이다.
	if( jobPos > pParentJob->GetSize() - 1 )
	{
		return NULL;
	}

	/// 전직 차수에 해당하는 직업의 코드드를 읽어간다.
	pParentJob->GetAt( &jobCode, jobPos );

	return jobCode;
}



void cStatusCalc_Client::CalcPlayerStatusSkillInfluenceAdd()
{
	cPointerHashMap::cIterator iter;

	cInfluenceObject* pInfluenceObject = NULL;
	sInfluenceScript* pInfluenceScript = NULL;
	cPointerHashMap* influenceMap = HERO->GetBufMap();
	if( influenceMap != NULL )
	{
		iter = influenceMap->Begin();
		while( iter != influenceMap->End() )
		{
			pInfluenceObject = (cInfluenceObject*)((*iter).mSecond);
			++iter;

			pInfluenceScript = SKILLSCRIPT->GetInfluenceInfo( pInfluenceObject->GetInfluenceIdx() );
			/// 지속적인 효과가 아닌경우만(데미지)
			if( pInfluenceScript->mTime1 == 0 )
			{
				if( pInfluenceScript->mStatusPlusIdx1 != 0 )
				{
					CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pInfluenceScript->mStatusPlusIdx1),
						(float)(pInfluenceScript->mValue1), true );
				}
			}
			/// 지속적인 효과가 아닌경우만(데미지)
			if( pInfluenceScript->mTime2 == 0 )
			{
				if( pInfluenceScript->mStatusPlusIdx2 != 0 )
				{
					CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pInfluenceScript->mStatusPlusIdx2),
						(float)(pInfluenceScript->mValue2), true  );
				}
			}
			if( pInfluenceScript->mStatusPlusIdx3 != 0 )
			{
				CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pInfluenceScript->mStatusPlusIdx3),
					(float)(pInfluenceScript->mValue3), true  );
			}
		}
	}

	influenceMap = HERO->GetDeBufMap();
	if( influenceMap != NULL )
	{
		iter = influenceMap->Begin();
		while( iter != influenceMap->End() )
		{
			pInfluenceObject = (cInfluenceObject*)((*iter).mSecond);
			++iter;

			pInfluenceScript = SKILLSCRIPT->GetInfluenceInfo( pInfluenceObject->GetInfluenceIdx() );
			/// 지속적인 효과가 아닌경우만(데미지)
			if( pInfluenceScript->mTime1 == 0 )
			{
				if( pInfluenceScript->mStatusPlusIdx1 != 0 )
				{
					CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pInfluenceScript->mStatusPlusIdx1),
						(float)(pInfluenceScript->mValue1), true );
				}
			}
			if( pInfluenceScript->mStatusPlusIdx2 != 0 )
			{
				CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pInfluenceScript->mStatusPlusIdx2),
					(float)(pInfluenceScript->mValue2), true  );
			}
			if( pInfluenceScript->mStatusPlusIdx3 != 0 )
			{
				CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pInfluenceScript->mStatusPlusIdx3),
					(float)(pInfluenceScript->mValue3), true  );
			}
		}
	}
}



void cStatusCalc_Client::CalcPlayerStatusSkillPassiveAdd()
{

	cPointerHashMap::cIterator iter;

	unsigned long skillIdx = 0;
	sKeepSkill* pKeepSkill = NULL;

	sPlayerSkillBaseInfo* pSkillInfo = NULL;
	sPlayerSkillStepInfo* pSkillStep = NULL;

	cPointerHashMap* keepSkillMap = SKILLMAN->GetKeepSkillMap();
	if( keepSkillMap != NULL )
	{
		iter = keepSkillMap->Begin();
		while( iter != keepSkillMap->End() )
		{
			skillIdx = (*iter).mFirst;
			pKeepSkill = (sKeepSkill*)((*iter).mSecond);
			if( pKeepSkill == NULL )
			{
				assert(NULL);
				return;
			}
			++iter;

			pSkillInfo = SKILLSCRIPT->GetPlayerSkillInfo( skillIdx );

			/// 패시브만 효과값 적용
			if( pSkillInfo->mType != eSKILLTYPE_PASSIVE )
			{
				continue;
			}

			if( pSkillInfo->mStepCount <= pKeepSkill->mStep )
			{
				assert(0);
			}

			pSkillStep = &pSkillInfo->mpSetpInfoArray[ pKeepSkill->mStep ];


			/// 내 장비가 맞는지 체크
			bool IsEquipment = true;
			if( pSkillInfo->mUseEquipment )
			{
				cItem rightWeapon = ITEMMAN->GetHeroRightWeapon();
				int rType = rightWeapon.GetDefine()? rightWeapon.GetDefine()->GetSubType() : -1;
				cItem leftWeapon = ITEMMAN->GetHeroLeftWeapon();
				int lType = leftWeapon.GetDefine()? leftWeapon.GetDefine()->GetSubType() : -1;

				/// 착용 장비 체크
				switch( pSkillInfo->mUseEquipment )
				{
				case eEQUIPTYPE_SWORD:
					if( rType != ITEM_WEAPON_SWORD )
						IsEquipment = false;
					break;
				case eEQUIPTYPE_LONGSWORD:
					if( rType != ITEM_WEAPON_BLADE )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_DOUBLESWORD:
					if( rType != ITEM_WEAPON_DUAL )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_SHORTSWORD:
					if( rType != ITEM_WEAPON_CUTTER )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_GUN:
					if( rType != ITEM_WEAPON_GUN )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_STAFF:
					if( rType != ITEM_WEAPON_STAFF )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_SHIELD:
					if( lType != ITEM_WEAPON_SHIELD )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_SWORD_LONGSWORD:
					if( rType != ITEM_WEAPON_SWORD &&
						rType != ITEM_WEAPON_BLADE )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_SWORD_DOUBLESWORD:
					if( rType != ITEM_WEAPON_SWORD &&
						rType != ITEM_WEAPON_DUAL )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_LONGSWORD_DOUBLESWORD:
					if( rType != ITEM_WEAPON_BLADE &&
						rType != ITEM_WEAPON_DUAL )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_SWORD_LONGSWORD_DOUBLESWORD:
					if( rType != ITEM_WEAPON_SWORD &&
						rType != ITEM_WEAPON_BLADE &&
						rType != ITEM_WEAPON_DUAL )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_SHORTSWORD_GUN:
					if( rType != ITEM_WEAPON_CUTTER &&
						rType != ITEM_WEAPON_GUN )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_CLOTH:
					if( HERO->GetArmorSets() != ARMOR_SETS_ROBES )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_LIGHTARMOR:
					if( HERO->GetArmorSets() != ARMOR_SETS_LIGHT_ARMOR )
						IsEquipment =  false;
					break;
				case eEQUIPTYPE_HEAVYARMOR:
					if( HERO->GetArmorSets() != ARMOR_SETS_HEAVY_ARMOR )
						IsEquipment =  false;
					break;
				}
			}

			if( IsEquipment == true )
			{
				if( pSkillStep->mApplyValueType1 != 0 )
				{
					CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pSkillStep->mApplyValueType1),
						(float)(pSkillStep->mApplyValue1), false );
				}
				if( pSkillStep->mApplyValueType2 != 0 )
				{
					CalcPlayerStatusItemSkillAddDetail( (eSTATUS_PLUS)(pSkillStep->mApplyValueType2),
						(float)(pSkillStep->mApplyValue2), false );
				}
			}
		}
	}
}



void cStatusCalc_Client::CalcPlayerStatusItemAdd()
{
	bool colorChange = false;
	sEquipAbility* pEquipAbility = ITEMMAN->GetBasicAbil();
	if( pEquipAbility == NULL )
		return;

	pEquipAbility = ITEMMAN->GetBasicAbil();
	colorChange = true;

	if( pEquipAbility->mOptStr != 0 )	/// 증가:힘
	{
		CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_STR_PLUS, (float)pEquipAbility->mOptStr, colorChange );
	}
	if( pEquipAbility->mOptDex != 0 )	/// 증가:민첩
	{
		CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_DEX_PLUS, (float)pEquipAbility->mOptDex, colorChange );
	}
	if( pEquipAbility->mOptCon != 0 )	/// 증가:체력
	{
		CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_CON_PLUS, (float)pEquipAbility->mOptCon, colorChange );
	}
	if( pEquipAbility->mOptInt != 0 )	/// 증가:지능
	{
		CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_INT_PLUS, (float)pEquipAbility->mOptInt, colorChange );
	}
	if( pEquipAbility->mOptWis != 0 )	/// 증가:지혜
	{
		CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_WIS_PLUS, (float)pEquipAbility->mOptWis, colorChange );
	}

	if( pEquipAbility->mOptPlusWei != 0 )	/// 증가:무게
	{
		CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_WEIGHT_PLUS, (float)pEquipAbility->mOptPlusWei, colorChange );
	}
	//if( pEquipAbility->mOptPlusMov != 0 )	/// 증가:이동속도
	//{
	//	CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_SPD_PLUS, (float)pEquipAbility->mOptPlusMov, colorChange );
	//}
	//if( pEquipAbility->mOptPlusMaxHp != 0 )	/// 증가:최대HP 
	//{
	//	CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_HP_PLUS, (float)pEquipAbility->mOptPlusMaxHp, colorChange );
	//}
	//if( pEquipAbility->mOptPlusMaxMp != 0 )	/// 증가:최대MP 
	//{
	//	CalcPlayerStatusItemSkillAddDetail( eSTATUSPLUS_MP_PLUS, (float)pEquipAbility->mOptPlusMaxMp, colorChange );
	//}
}



void cStatusCalc_Client::CalcPlayerStatus()
{
	unsigned char level = HERO->GetLevel();
	ePLAYER_JOB job = HERO->GetJob();

	/// 전직클래스1 기준 레벨 
	unsigned char class1 = 30;
	/// 전직클래스2 기준 레벨
	unsigned char class2 = 70;

	sStatusBaseScript* pStatusBase = NULL;

	/// 자기 자신에 해당하는 직업의 statusbase 정보를 가져옴
	pStatusBase = STATUSSCRIPT->GetStatusBaseInfo( job );

	/// 자신에 해당하는 직업이 없으면 상위 직업을 읽어와서 처리한다.
	if( pStatusBase == NULL )
	{
		/// 상위 직업 배열을 읽어온다.
		tArray<unsigned long>* playerJobParent = GAMERESOURCEMAN->GetParentJob( job );
		if( playerJobParent == NULL )
		{
			/// 자신의 직업도 없는데 부모의 직업도 없으면 오류
			assert(NULL);
			return; 
		}
		else
		{

			/// 상위 직업이 있으면 
			for( int i = playerJobParent->GetSize() - 1 ; 0 <= i  ; --i )
			{
				/// 상위 직업코드로 스크립트 값을 읽어옴
				pStatusBase = STATUSSCRIPT->GetStatusBaseInfo( (*playerJobParent)[i] );
				if( pStatusBase != NULL )
				{
					break;
				}
			}

			assert(NULL);
		}
	}

	/// 입력 값 기본 스텟 수치로 적용 
	for( unsigned char i = ePLAYER_STATUS_STR ; i < ePLAYER_STATUS_LEVEL ; ++i )
	{
		mBaseStatus[i] = pStatusBase->mBaseStatus[i];
	}

	/// 전직 차수와 레벨에 따른 실제 적용 받아야할 직업코드
	unsigned long fixjob = job;

	sStatusMultiplScript* pStatusMultipl;

	/// 현재 레벨에서 1레벨까지 스텟 계산 ( 0레벨은 기본값 1레벨부터 증가치 )
	for( unsigned char j = 1 ; j <= level ; ++j )
	{

		/// 1레벨에서 1차전직레벨(30)전까지 기본직업 코드로 스텟 계산
		if( ( 1 <= j ) && ( j < class1 ) )
		{
			/// 상위 직업 리스트에서 1차전직 직업을 가져옴
			fixjob = GetParantJob( job, 0 );
			/// 없는 경우 현재 직업이 기본 직업이라 부모가 없는 경우임
			if( fixjob == NULL )
			{
				/// 현재 직업을 스텟 계산 기준 코드로 등록
				fixjob = job;
			}
		}

		/// 1차전직레벨(30)에서 2차전직레벨(70)까지 1차전직
		else if( ( class1 <= j ) && ( j < class2 ) )
		{
			/// 상위 직업 리스트에서 1차전직 직업을 가져옴
			fixjob = GetParantJob( job, 1 );
			/// 없는 경우 현재 직업이 1차 직업임
			if( fixjob == NULL )
			{
				fixjob = job;
			}
		}

		/// 2차전직레벨(30)에서 레벨 한계점 까지
		else if( class2 <= j )
		{
			/// 상위 직업 리스트에서 2차전직 직업을 가져옴
			fixjob = GetParantJob( job, 2 );
			/// 없는 경우 현재 직업이 2차 직업임
			if( fixjob == NULL )
			{
				fixjob = job;
			}
		}

		/// 현재 레벨에 맞는 직업 코드로 스텟 증가치를 얻어옴
		pStatusMultipl = STATUSSCRIPT->GetStatusMultiplInfo( fixjob );
		if( pStatusMultipl == NULL )
		{
			assert(NULL);
			return;
		}

		for( unsigned char i = ePLAYER_STATUS_STR ; i < ePLAYER_STATUS_LEVEL ; ++i )
		{
			/// 클래스기준에 따른 증가치 만큼 증가
			mBaseStatus[i] = mBaseStatus[i] + pStatusMultipl->mBaseStatus[i];
		}
	}
}



void cStatusCalc_Client::CalcPlayerExtStatus( ePLAYER_STATUS_EXT statusExt )
{
	ePLAYER_JOB job = HERO->GetJob();

	/// 플레이어의 스텟1 최종값을 읽어옴 + 레벨값까지
	float baseStatus[ePLAYER_STATUS_LEVEL_MAX];
	unsigned char i = ePLAYER_STATUS_STR;
	for( ; i < ePLAYER_STATUS_LEVEL ; ++i )
	{
		baseStatus[i] = mBaseStatus[i] + mBaseStatusPlus[i];
		if( baseStatus[i] < 0.0f )
			baseStatus[i] = 0.0f;
	}
	baseStatus[i] = HERO->GetLevel(); 

	/// 스텟의 계산 결과 값
	float			statusValue = 0.0f;

	/// 자연회복HP/MP 기본값은 [캐릭터스탯회복수치]에 더하지 않고 자연회복계산시 사용한다.
	if( statusExt == ePLAYER_STATUS_EXT_RECOVHP || statusExt == ePLAYER_STATUS_EXT_RECOVMP )
	{
		statusValue = 0.0f;
	}
	else
	{
		/// 자신의 직업과 스텟 구분이랑 같은 것이 있는지 체크
		statusValue = (float)STATUSSCRIPT->GetStatusExtBaseInfo( statusExt, job );
		//if( FloatToInt(statusValue) == 0 )
		//{
		//	if( playerJobParent != 0 )
		//	{
		//		/// 상위 직업이 있으면 
		//		for( int i = playerJobParent->GetSize() - 1 ; 0 <= i  ; --i )
		//		{
		//			/// 상위 직업코드로 스크립트 값을 읽어옴
		//			statusValue = (float)STATUSSCRIPT->GetStatusExtBaseInfo( statusExt, (*playerJobParent)[i] );

		//			if( FloatToInt(statusValue) != 0 )
		//			{
		//				break;
		//			}
		//		}
		//	}
		//	else
		//	{
		//		statusValue = 0.0f;
		//	}
		//}
	}

	/// 플레이어의 최상위(1차) 직업 기록
	tArray<unsigned long>* playerJobParent = GAMERESOURCEMAN->GetParentJob( job );
	unsigned long firstJob = HERO->GetJob();
	if( playerJobParent != NULL )
		firstJob = (*playerJobParent)[0];

	/// 1차 직업에 따라 공격력 스텟 비중치 읽어올 항목값 설정
	unsigned long plusStatus = 0;
	switch( firstJob )
	{		
	case ePLAYER_FIGHTER:	/// 파이터
	case ePLAYER_WARRIOR:	/// 워리어
		plusStatus = 0;
		break;
	case ePLAYER_RANGER:	/// 레인져
	case ePLAYER_ROGUE:		/// 로그
		plusStatus = 1;
		break;
	case ePLAYER_MAGE:		/// 메이지
	case ePLAYER_SHAMAN:	/// 샤먼
		plusStatus = 2;
		break;
	}

	float importance = 0.0f;
	for( unsigned char i = ePLAYER_STATUS_STR ; i < ePLAYER_STATUS_LEVEL_MAX ; ++i )
	{
		eEXT_MULTIPL chgStatusExt = eEXT_MULTIPL_MAX;
		switch( statusExt )
		{
		case ePLAYER_STATUS_EXT_ATK:
			chgStatusExt = (eEXT_MULTIPL)( eEXT_MULTIPL_ATK_FIGHTER + plusStatus );		/// 근거리, 원거리, 마법 직업에 따른 공격력 항목 설정
			break;
		case ePLAYER_STATUS_EXT_RATK:
			chgStatusExt = (eEXT_MULTIPL)( eEXT_MULTIPL_RATK_FIGHTER + plusStatus );
			break;
		case ePLAYER_STATUS_EXT_MATK:
			chgStatusExt = (eEXT_MULTIPL)( eEXT_MULTIPL_MATK_FIGHTER + plusStatus );
			break;
		case ePLAYER_STATUS_EXT_DEF:		chgStatusExt = eEXT_MULTIPL_DEF;		break;	/// 물리 방어력
		case ePLAYER_STATUS_EXT_MDEF:		chgStatusExt = eEXT_MULTIPL_MDEF;		break;	/// 마법 방어력
		case ePLAYER_STATUS_EXT_CRI:		chgStatusExt = eEXT_MULTIPL_CRI;		break;	/// 물리 크리티컬 수치
		case ePLAYER_STATUS_EXT_MCRI:		chgStatusExt = eEXT_MULTIPL_MCRI;		break;	/// 마법 크리티컬 수치
		case ePLAYER_STATUS_EXT_MAXHP:		chgStatusExt = eEXT_MULTIPL_MAXHP;		break;	/// HP 
		case ePLAYER_STATUS_EXT_MAXMP:		chgStatusExt = eEXT_MULTIPL_MAXMP;		break;	/// MP
		case ePLAYER_STATUS_EXT_RECOVHP:	chgStatusExt = eEXT_MULTIPL_RECOVHP;	break;	/// HP 회복 속도
		case ePLAYER_STATUS_EXT_RECOVMP:	chgStatusExt = eEXT_MULTIPL_RECOVMP;	break;	/// MP 회복 속도
		case ePLAYER_STATUS_EXT_HIT:		chgStatusExt = eEXT_MULTIPL_HIT;		break;	/// 명중 수치
		case ePLAYER_STATUS_EXT_MHIT:		chgStatusExt = eEXT_MULTIPL_MHIT;		break;	/// 마법 명중
		case ePLAYER_STATUS_EXT_AVOID:		chgStatusExt = eEXT_MULTIPL_AVOID;		break;	/// 회피 수치
		case ePLAYER_STATUS_EXT_WEIGHT:		chgStatusExt = eEXT_MULTIPL_WEIGHT;		break;	/// 무게 
		case ePLAYER_STATUS_EXT_RANGE:		chgStatusExt = eEXT_MULTIPL_RANGE;		break;	/// 사정거리
		case ePLAYER_STATUS_EXT_RRANGE:		chgStatusExt = eEXT_MULTIPL_RRANGE;		break;	/// 방출혈사정거리
		case ePLAYER_STATUS_EXT_COOLTIME:	chgStatusExt = eEXT_MULTIPL_COOLTIME;	break;	/// 쿨타임
		case ePLAYER_STATUS_EXT_SPD:		chgStatusExt = eEXT_MULTIPL_SPD;		break;	/// 이동속도
		case ePLAYER_STATUS_EXT_ASPD:		chgStatusExt = eEXT_MULTIPL_ASPD;		break;	/// 공격 속도	
		}

		/// 베이스 스텟을 비중과 곱한다.
		importance = STATUSSCRIPT->GetStatusExtMultiplInfo( chgStatusExt, (ePLAYER_STATUS)i );
		statusValue += baseStatus[i] * importance;
	}

	/// 결과 값을 기록
	mExtStatus[statusExt] = mExtStatus[statusExt] + statusValue;
	if( mExtStatus[statusExt] < 0.0f ) 
		mExtStatus[statusExt] = 0.0f;

}



void cStatusCalc_Client::CalcPlayerInit()
{
	CalcPlayerBaseOnly();
	CalcPlayerExtensionOnly();
	CalcPlayerGlobal();
}



void cStatusCalc_Client::CalcPlayerBaseGlobal()
{
	CalcPlayerBaseOnly();
	CalcPlayerGlobal();
}



void cStatusCalc_Client::CalcPlayerExtensionGlobal()
{
	CalcPlayerExtensionOnly();
	CalcPlayerGlobal();
}



void  cStatusCalc_Client::CalcPlayerGlobal()
{

	/// 확장 스텟 베이스 초기화
	for( int i = ePLAYER_STATUS_EXT_ATK ; ePLAYER_STATUS_EXT_MAX > i ; ++i )
	{
		mExtStatus[i] = 0;
	}

	/// 확장 스텟 최종값
	for( int i = ePLAYER_STATUS_EXT_ATK ; ePLAYER_STATUS_EXT_MAX > i ; ++i )
	{
		mExtStatusLast[i] = 0;
	}

	float num1, num2, num3, num4;
	float valueA, valueB, valueC;

	sEquipAbility* pItem = ITEMMAN->GetBasicAbil();

	for( unsigned char i = ePLAYER_STATUS_EXT_ATK ; i < ePLAYER_STATUS_EXT_MAX ; ++i )
	{
		/// 스크립트에서 읽어들인 순수한 확장 스텟값 계산
		CalcPlayerExtStatus( (ePLAYER_STATUS_EXT)i );

		/// 최종 스텟 계산전 가감산 할 항목 적용
		switch( (ePLAYER_STATUS_EXT)i )
		{
			/// 근거리 물리 공격
		case ePLAYER_STATUS_EXT_ATK:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 301 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 302 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 303 );

				/// A =	캐릭터 스탯 근거리 공격력
				/// B =	아이템 물리 공격력 + ( [캐릭터] Lv * {num301} )
				/// C =	(({num302} + ( 버프성 근거리 공격력[%]값 + 아이템옵션값[%]값 ) / {num303})
				///	((A + B ) * C) + ( 버프성 근거리 공격력[+-]값 + 아이템옵션값[+-]값 )
				valueA = mExtStatus[i];
				valueB = ( pItem->mPhysicMinAttack ) + ( HERO->GetLevel() * num1 );
				valueC = ( ( num2 + mExtStatusPer[i] + pItem->mOptPercentPhysicAttack ) / num3 );
				mExtStatusLast[i] = ( ( valueA + valueB ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusPhysicAttack;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_ATKMin, mExtStatusLast[i] );

				valueB = pItem->mPhysicMaxAttack + ( HERO->GetLevel() * num1 );
				valueC = ( ( num2 + mExtStatusPer[i] + pItem->mOptPercentPhysicAttack ) / num3 );
				mExtStatusLast[i] = ( ( valueA + valueB ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusPhysicAttack;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_ATKMax, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentPhysicAttack != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentPhysicAttack, mExtStatusLast[i] );
				if( pItem->mOptPlusPhysicAttack != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusPhysicAttack, mExtStatusLast[i] );

				mExtStatusLast[i] = 0.0f;
			}
			break;
			/// 원거리 물리 공격
		case ePLAYER_STATUS_EXT_RATK:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 331 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 332 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 333 );

				/// A =	캐릭터 스탯 원거리 공격력
				/// B =	아이템 물리 공격력 + ( [캐릭터] Lv * {num331} )
				/// C =	(({num332} + ( 버프성 근거리 공격력[%]값 + 아이템옵션값[%]값 ) / {num333})
				///	((A + B ) * C) + ( 버프성 근거리 공격력[+-]값 + 아이템옵션값[+-]값 )
				valueA = mExtStatus[i];
				valueB = pItem->mPhysicMinAttack + ( HERO->GetLevel() * num1 );
				valueC = ( ( num2 + mExtStatusPer[i] + pItem->mOptPercentPhysicAttack ) / num3 );
				mExtStatusLast[i] = ( ( valueA + valueB ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusPhysicAttack;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_RATKMin, mExtStatusLast[i] );

				valueB = pItem->mPhysicMaxAttack + ( HERO->GetLevel() * num1 );
				valueC = ( ( num2 + mExtStatusPer[i] + pItem->mOptPercentPhysicAttack ) / num3 );
				mExtStatusLast[i] = ( ( valueA + valueB ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusPhysicAttack;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_RATKMax, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentPhysicAttack != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentPhysicAttack, mExtStatusLast[i] );
				if( pItem->mOptPlusPhysicAttack != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusPhysicAttack, mExtStatusLast[i] );

				mExtStatusLast[i] = 0.0f;
			}
			break;
			/// 물리 방어력
		case ePLAYER_STATUS_EXT_DEF:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 401 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 402 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 403 );
				num4 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 404 );

				// A =	캐릭터 스탯물리 방어력
				// B =	아이템 물리 방어력
				// C =	(( {num401} + ( 버프성 물리 방어력[%]값 + 아이템옵션[%]값 ) ) / {num402} )
				// D =	((A /{num403}  + B /{num404}) * C) + ( 버프성 물리 방어력[+-]값 + 아이템옵션[+-]값 )
				valueA = mExtStatus[i];
				valueB = pItem->mPhysicDefense;
				valueC = ( ( num1 + ( mExtStatusPer[i] + pItem->mOptPercentPhysicDefense ) ) / num2 );
				mExtStatusLast[i] = ( ( valueA / num3 + valueB / num4 ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusPhysicDefense;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentPhysicDefense != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentPhysicDefense, mExtStatusLast[i] );
				if( pItem->mOptPlusPhysicDefense != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusPhysicDefense, mExtStatusLast[i] );
			}
			break;
			/// 마법 공격
		case ePLAYER_STATUS_EXT_MATK:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 361 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 362 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 363 );
				num4 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 364 );

				/// A =	캐릭터 스탯 마법 공격력 / {num361}
				/// B =	아이템 마법 공격력 + ( [캐릭터] Lv * {num362} )
				/// C =	(({num363} + ( 버프성 마법 공격력[%]값 + 아이템옵션[%]값 ) ) / {num364})
				///	((A + B ) * C) + ( 버프성 마법 공격력[+-]값 + 아이템옵션[+-]값 )
				valueA = mExtStatus[i] / num1;
				valueB = pItem->mMagicMinAttack + ( HERO->GetLevel() * num2 );
				valueC = ( ( num3 + ( mExtStatusPer[i] + pItem->mOptPercentMagicAttack ) ) / num4 );
				mExtStatusLast[i] = ( ( valueA + valueB ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusMagicAttack;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_MATKMin, mExtStatusLast[i] );

				valueB = pItem->mMagicMaxAttack + ( HERO->GetLevel() * num2 );
				valueC = ( ( num3 + ( mExtStatusPer[i] + pItem->mOptPercentMagicAttack ) ) / num4 );
				mExtStatusLast[i] = ( ( valueA + valueB ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusMagicAttack;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_MATKMax, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentMagicAttack != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentMagicAttack, mExtStatusLast[i] );
				if( pItem->mOptPlusMagicAttack != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusMagicAttack, mExtStatusLast[i] );

				mExtStatusLast[i] = 0.0f;
			}
			break;
			/// 마법 방어력
		case ePLAYER_STATUS_EXT_MDEF:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 431 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 432 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 433 );
				num4 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 434 );

				// A =	캐릭터 스탯마법 방어력
				// B =	아이템 마법 방어력
				// C =	(( {num431} + ( 버프성 마법 방어력[%]값 + 아이템옵션[%]값 ) ) / {num432} )
				// D =	((A /{num433}  + B /{num434}) * C) + ( 버프성 물리 방어력[+-]값 + 아이템옵션[+-]값 )
				valueA = mExtStatus[i];
				valueB = pItem->mMagicDefense;
				valueC = ( ( num1 + ( mExtStatusPer[i] + pItem->mOptPercentMagicDefense ) ) / num2 );
				mExtStatusLast[i] = ( ( valueA / num3 + valueB / num4 ) * valueC ) + mExtStatusPlus[i] + pItem->mOptPlusMagicDefense;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentMagicDefense != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentMagicDefense, mExtStatusLast[i] );
				if( pItem->mOptPlusMagicDefense != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusMagicDefense, mExtStatusLast[i] );

			}
			break;
			/// 물리 공격 크리
		case ePLAYER_STATUS_EXT_CRI:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 201 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 202 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 203 );
				num4 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 204 );

				/// A =	[공격자] 캐릭터 스탯 물리 크리티컬 수치 + 아이템 물리 크리티컬 수치
				///	( A * {num201} ) * (({num202} + ( 버프성 물리 크리티컬 [%]값 + 아이템옵션[%]값 ) ) /
				///	{num203}) + ( 버프성 물리 크리티컬 수치[+-]값 + 아이템옵션[+-]값 ) * {num204} )
				valueA = mExtStatus[i] + pItem->mPhysicCritical;
				mExtStatusLast[i] = ( valueA * num1 ) * ( ( num2 + ( mExtStatusPer[i] + pItem->mOptPercentPhysicCritical ) ) / num3 ) +
					( ( mExtStatusPlus[i] + pItem->mOptPlusPhysicCritical ) * num4 );

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentPhysicCritical != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentPhysicCritical, mExtStatusLast[i] );
				if( pItem->mOptPlusPhysicCritical != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusPhysicCritical, mExtStatusLast[i] );
			}
			break;
			///	마법 공격 크리
		case ePLAYER_STATUS_EXT_MCRI:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 231 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 232 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 233 );
				num4 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 234 );

				/// A =	[공격자] 캐릭터 스탯 마법 크리티컬 수치 + 아이템 마법 크리티컬 수치
				///	( A * {num231} ) * (({num232} + ( 버프성 마법 크리티컬 [%]값 + 아이템옵션[%]값 ) ) / 
				/// {num233}) + ( ( 버프성 마법 크리티컬 수치[+-]값 + 아이템옵션[+-]값 ) * {num234} )
				valueA = mExtStatus[i] + pItem->mMagicCritical;
				mExtStatusLast[i] = ( valueA * num1 ) * ( ( num2 + ( mExtStatusPer[i] + pItem->mOptPercentMagicCritical ) ) / num3 ) + 
					( ( mExtStatusPlus[i] + pItem->mOptPlusMagicCritical ) * num4 );

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentMagicCritical != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentMagicCritical, mExtStatusLast[i] );
				if( pItem->mOptPlusMagicCritical != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusMagicCritical, mExtStatusLast[i] );
			}break;
			/// 최대 HP
		case ePLAYER_STATUS_EXT_MAXHP:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 20 );

				/// 기본 hp량 + ( 레벨 * num1 )
				mExtStatus[i] = mExtStatus[i] + ( HERO->GetLevel() * num1 );    
				mExtStatusLast[i] = mExtStatus[i] * ( ( 100 + ( mExtStatusPer[i] + pItem->mOptPercentMaxHp ) ) / 100 )
					+ mExtStatusPlus[i] + pItem->mOptPlusMaxHp;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );
			}
			break;
			/// 최대 MP
		case ePLAYER_STATUS_EXT_MAXMP:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 20 );

				mExtStatusLast[i] = mExtStatus[i] * ( ( 100 + ( mExtStatusPer[i] + pItem->mOptPercentMaxMp ) ) / 100 ) + 
					mExtStatusPlus[i] + pItem->mOptPlusMaxMp;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );
			}
			break;
			/// HP 자연 회복량
		case ePLAYER_STATUS_EXT_RECOVHP:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1001 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1002 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1003 );

				float defaultValueHP = (float)STATUSSCRIPT->GetStatusExtBaseInfo( (ePLAYER_STATUS_EXT)i, HERO->GetJob() );

				/// A =	클래스 기본값
				///	B =	( 캐릭터 스탯 회복 수치 * {num1001} ) * (( {num1002} + 버프성 HP회복 [%]값 + 아이템옵션[%]값 ) / {num1003} ) + 아이템에 의한 HP 회복 수치 총합
				///	A + B + 버프성 HP회복 [+-]값
				valueA = defaultValueHP;
				valueB = ( mExtStatus[i] * num1 ) * ( ( num2 + ( mExtStatusPer[i] + pItem->mOptPercentHp ) ) / num3 ) + pItem->mOptPlusHp;
				mExtStatusLast[i] = valueA + valueB + mExtStatusPlus[i];

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				if( HERO->IsSitDownCalc() == true )
					mExtStatusLast[i] *= STATUSSCRIPT->GetDamageCalcNumericalInfo( 10 );

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentHp != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentHp, mExtStatusLast[i] );
				if( pItem->mOptPlusHp != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusHp, mExtStatusLast[i] );
			}
			break;
			/// MP 자연 회복량
		case ePLAYER_STATUS_EXT_RECOVMP:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1101 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1102 );
				num3 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1103 );

				float defaultValueMP = (float)STATUSSCRIPT->GetStatusExtBaseInfo( (ePLAYER_STATUS_EXT)i, HERO->GetJob() );

				/// A =	클래스 기본값
				///	B =	( 캐릭터 스탯 회복 수치 * {num1101} ) * (( {num1102} + ( 버프성 MP회복 [%]값 + 아이템옵션[%]값 ) ) / {num1103} ) + 아이템에 의한 MP 회복 수치 총합
				///	A + B + 버프성 MP회복 [+-]값
				valueA = defaultValueMP;
				valueB = ( mExtStatus[i] * num1 ) * ( ( num2 + mExtStatusPer[i] + pItem->mOptPercentMp ) / num3 ) + pItem->mOptPlusMp;
				mExtStatusLast[i] = valueA + valueB + mExtStatusPlus[i];

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				if( HERO->IsSitDownCalc() == true )
					mExtStatusLast[i] *= STATUSSCRIPT->GetDamageCalcNumericalInfo( 10 );

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentMp != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentMp, mExtStatusLast[i] );
				if( pItem->mOptPlusMp != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusMp, mExtStatusLast[i] );
			}
			break;
			/// 물리 공격 성공
		case ePLAYER_STATUS_EXT_HIT:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 101 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 102 );

				/// ( [공격자] 캐릭터 스탯 명중 수치 + 아이템 명중 수치 ) * (({num101} + ( 버프성 명중 수치[%]값 + + 아이템옵션[%]값 ) ) / {num102}) + 
				/// 버프성 명중 수치[+-]값 + 아이템옵션[+-]값 
				mExtStatusLast[i] = ( mExtStatus[i] + pItem->mPhysicAttackRate ) * 
					( ( num1 + ( mExtStatusPer[i] + pItem->mOptPercentPhysicAttackRate ) ) / num2 ) + mExtStatusPlus[i] + pItem->mOptPlusPhysicAttackRate;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentPhysicAttackRate != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentPhysicAttackRate, mExtStatusLast[i] );
				if( pItem->mOptPlusPhysicAttackRate != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusPhysicAttackRate, mExtStatusLast[i] );
			}
			break;
			/// 마법 공격 성공
		case ePLAYER_STATUS_EXT_MHIT:
			{
				/// 마법은 스텟사용 안함
				mExtStatusLast[i] = 0.0f;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );
			}
			break;
			/// 회피율
		case  ePLAYER_STATUS_EXT_AVOID:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 105 );
				num2 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 106 );

				///	( [방어자] 캐릭터 스탯 회피 수치 + 아이템 회피 수치 ) * (({num105} + ( 버프성 회피 수치[%]값 + 아이템옵션[%]값 ) ) / {num106}) + 
				/// 버프성 회피 수치[+-]값 + 아이템옵션[+-]값 )
				mExtStatusLast[i] = ( mExtStatus[i] + pItem->mOptPlusDod ) *
					( ( num1 + ( mExtStatusPer[i] + pItem->mOptPercentDod ) ) / num2 ) + mExtStatusPlus[i] + pItem->mOptPlusDod;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );

				/// 확장항목에 수치가 있는경우 색변환
				if( pItem->mOptPercentDod != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPercentDod, mExtStatusLast[i] );
				if( pItem->mOptPlusDod != 0 )
					SetExtStatusInfoType( (ePLAYER_STATUS_EXT)i, pItem->mOptPlusDod, mExtStatusLast[i] );
			}
			break;
			/// 일반공격 속도
		case ePLAYER_STATUS_EXT_ASPD:
			{
				mExtStatusLast[i] = ( 100 + pItem->mAttackSpeed + mExtStatusPer[i] ) / 100;

				if( mExtStatusLast[i] < 0.1f )
					mExtStatusLast[i] = 0.1f;

				if( mExtStatusLast[i] > 2.0f )
					mExtStatusLast[i] = 2.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );                  
			}break;
			/// 힐 회복량
		case ePLAYER_STATUS_EXT_HEAL:
			{
				num1 = STATUSSCRIPT->GetDamageCalcNumericalInfo( 1203 );

				///	( 캐릭터 스탯 마법 공격력 * 0.5 ) + 아이템에 의한 스킬회복량 증가 수치 총합
				mExtStatusLast[i] = HERO->GetStatus2()->mMagicMinAttack * num1;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_HEALMin, mExtStatusLast[i] );

				mExtStatusLast[i] = HERO->GetStatus2()->mMagicMaxAttack * num1;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( ePLAYER_STATUS_EXT_HEALMax, mExtStatusLast[i] );

				mExtStatusLast[i] = 0.0f;
			}
			break;
			/// 무게
		case ePLAYER_STATUS_EXT_WEIGHT:
			{
				mExtStatusLast[i] = mExtStatus[i] * ( ( 100.0f + ( mExtStatusPer[i] + pItem->mOptPercentWei ) ) / 100.0f ) + 
					mExtStatusPlus[i] + pItem->mOptPlusWei;

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );
			}
			break;
		default:
			{
				mExtStatusLast[i] = mExtStatus[i] * ( ( 100.0f + mExtStatusPer[i] ) / 100.0f ) + mExtStatusPlus[i];

				if( mExtStatusLast[i] < 0.0f )
					mExtStatusLast[i] = 0.0f;

				HERO->SetStatus2( (ePLAYER_STATUS_EXT)i, mExtStatusLast[i] );
			}
			break;
		}
	}

	/// 최종 결과를 플레이어에 기록
	for( unsigned char i = ePLAYER_STATUS_STR ; i < ePLAYER_STATUS_LEVEL ; ++i )
	{
		HERO->SetStatus1( (ePLAYER_STATUS)i, mBaseStatus[i] );
		HERO->SetStatus1Plus( (ePLAYER_STATUS)i, mBaseStatusPlus[i] );
	}

	for( unsigned char i = ePLAYER_STATUS_EXT_ADD_EXPADDPER ; i < ePLAYER_STATUS_EXT_ADD_MAX ; ++i )
	{
		HERO->SetStatusEtc( (ePLAYER_STATUS_EXT_ADD)i, mExtAddStatus[i] );
	}

}



float cStatusCalc_Client::GetStatus2Plus( ePLAYER_STATUS_EXT status2 )
{ 
	if( status2 >= ePLAYER_STATUS_EXT_MAX )
	{
		assert(NULL);
		return 0.0f;
	}

	return mExtStatusPlus[status2];
}


float cStatusCalc_Client::GetStatus2Per( ePLAYER_STATUS_EXT status2 )
{ 
	if( status2 >= ePLAYER_STATUS_EXT_MAX )
	{
		assert(NULL);
		return 0.0f;
	}

	return mExtStatusPer[status2];
}
