4904 lines
No EOL
305 KiB
C++
4904 lines
No EOL
305 KiB
C++
#include "StdAfx.h"
|
||
#include "DnSkill.h"
|
||
#include "DnTableDB.h"
|
||
#include "DnItemTask.h"
|
||
#include "IDnSkillUsableChecker.h"
|
||
#include "IDnSkillProcessor.h"
|
||
#include "DnDivideSEArgumentByTargets.h"
|
||
#include "DnPlayerActor.h"
|
||
#include "DnBlow.h"
|
||
#include "TaskManager.h"
|
||
#include "DnPartyTask.h"
|
||
#include "DNUserSession.h"
|
||
#include "DnPlayAniProcess.h"
|
||
#include "DnPartialPlayProcessor.h"
|
||
#include "DnApplySEWhenActionSetBlowEnabledProcessor.h"
|
||
#include "DnChangeActionStrProcessor.h"
|
||
#include "DnChangeActionStrByBubbleProcessor.h"
|
||
#include "DnStateEffectApplyOnOffByBubbleProcessor.h"
|
||
#include "DnStateBlow.h"
|
||
#include "DnBubbleSystem.h"
|
||
#include "DnObserverEventMessage.h"
|
||
#include "DnPingpongBlow.h"
|
||
#include "DnBasicBlow.h"
|
||
#include "DnHealingBlow.h"
|
||
#include "DnHPIncBlow.h"
|
||
#include "DnInvincibleAtBlow.h"
|
||
#include "DnProbabilityChecker.h"
|
||
#include "DnCreateBlow.h"
|
||
#include "DnAllowedSkillsBlow.h"
|
||
#include "DnMonsterActor.h"
|
||
#include "DnProjectile.h"
|
||
#include "DnAdditionalStateInfoBlow.h"
|
||
#include "DnAddStateBySkillGroupBlow.h"
|
||
#include "DnTransformBlow.h"
|
||
#include "DnBloodSuckingBlow.h"
|
||
#include "DnOrderMySummonedMonsterBlow.h"
|
||
|
||
#if defined(PRE_FIX_NEXTSKILLINFO)
|
||
#include "DNGameDataManager.h"
|
||
#endif // PRE_FIX_NEXTSKILLINFO
|
||
|
||
#if defined(PRE_FIX_46381)
|
||
#include "DnContinueBaseMPIncBlow.h"
|
||
#endif // PRE_FIX_46381
|
||
|
||
using namespace BubbleSystem;
|
||
using namespace boost;
|
||
|
||
DECL_MULTISMART_PTR_STATIC( CDnSkill, MAX_SESSION_COUNT, 100 )
|
||
|
||
|
||
CDnSkill::CDnSkill( DnActorHandle hActor ) : CMultiSmartPtrBase< CDnSkill, MAX_SESSION_COUNT >(hActor->GetRoom()),
|
||
m_hActor( hActor ),
|
||
m_LastTimeToggleMPDecreaseTime( 0 ),
|
||
m_bToggle( false ),
|
||
m_bAura( false ),
|
||
m_bItemSkill( false ),
|
||
m_fPassiveActionSkillLength( 0.0f ),
|
||
m_eElement( CDnState::ElementEnum_Amount ),
|
||
m_iNextLevelSkillPoint( -1 ),
|
||
m_bChainingPassiveSkill( false ),
|
||
m_bAppliedPassiveSelfBlows( false ),
|
||
m_bTempSkill( false )
|
||
{
|
||
SecureZeroMemory( m_iNeedItemID, sizeof(m_iNeedItemID) );
|
||
SecureZeroMemory( m_iNeedItemDecreaseCount, sizeof(m_iNeedItemDecreaseCount) );
|
||
SecureZeroMemory( m_fHPConsumeType, sizeof(m_fHPConsumeType) );
|
||
SecureZeroMemory( m_fMPConsumeType, sizeof(m_fMPConsumeType) );
|
||
SecureZeroMemory( m_iNeedHP, sizeof(m_iNeedHP) );
|
||
SecureZeroMemory( m_iNeedMP, sizeof(m_iNeedMP) );
|
||
SecureZeroMemory( m_iIncreaseRange, sizeof(m_iIncreaseRange) );
|
||
SecureZeroMemory( m_iDecreaseHP, sizeof(m_iDecreaseHP) );
|
||
SecureZeroMemory( m_iDecreaseMP, sizeof(m_iDecreaseMP) );
|
||
SecureZeroMemory( m_fOriginalDelayTime, sizeof(m_fOriginalDelayTime) );
|
||
SecureZeroMemory( m_fDelayTime, sizeof(m_fDelayTime) );
|
||
|
||
m_iSkillID = 0;
|
||
m_iSkillLevelID = 0;
|
||
m_iDissolvable = 0;
|
||
m_iDuplicateCount = 0;
|
||
m_iSkillDuplicateMethod = 0;
|
||
m_iEffectDuplicateMethod = 0;
|
||
|
||
m_iLevel = 0;
|
||
m_iMaxLevel = 0;
|
||
|
||
m_eSkillType = SkillTypeEnum::Active;
|
||
m_eDurationType = DurationTypeEnum::Instantly;
|
||
m_eTargetType = TargetTypeEnum::Self;
|
||
m_iLevelLimit = 0;
|
||
|
||
m_fLeftDelayTime = 0.f;
|
||
m_fCoolTime = 0.f;
|
||
m_iAdditionalThreat = 0;
|
||
|
||
m_iCPScore = 0;
|
||
|
||
m_pEffectAction = NULL;
|
||
|
||
m_fOnceDelayTime = 0.0f;
|
||
m_fOnceElapsedDelayTime = 0.0f;
|
||
m_bEquipItemSkill = false;
|
||
m_iEquipIndex = -1;
|
||
|
||
m_fCoolTimeAdjustBlowValue = 1.0f;
|
||
|
||
m_fStartSuperArmor = 0.0f;
|
||
m_bStartCanHit = true;
|
||
|
||
m_fResetCooltime = 0.0f;
|
||
|
||
m_dwLastUseSkillTimeStamp = 0;
|
||
|
||
m_iExclusiveID = 0;
|
||
|
||
m_iSelectedSkillLevelDataApplyType = PVE; // 디폴트는 pve 이다.
|
||
|
||
m_iBaseSkillID = 0;
|
||
m_iAppliedEnchantPassiveSkillID = 0;
|
||
|
||
m_nPriority = 0;
|
||
|
||
m_nItemID = -1;
|
||
|
||
m_fCoolTimeMultipier = 1.0f;
|
||
|
||
m_isIgnoreImmuneBackup = false;
|
||
|
||
m_nLevelUpValue = 0;
|
||
|
||
#if defined(PRE_ADD_PREFIX_SYSTE_RENEW)
|
||
m_nPrefixSkillType = -1;
|
||
#endif // PRE_ADD_PREFIX_SYSTE_RENEW
|
||
|
||
m_iGlobalSkillGroupID = 0;
|
||
SecureZeroMemory( m_afGlobalCoolTime, sizeof(m_afGlobalCoolTime) );
|
||
m_fAnotherGlobalSkillCoolTime = 0.0f;
|
||
|
||
m_nAnotherGlobakSkillID = 0;
|
||
|
||
#if defined( PRE_ADD_ACADEMIC )
|
||
m_iSummonerDecreaseSP = 0;
|
||
m_iSummonerDecreaseSPSkillID = 0;
|
||
#endif // #if defined( PRE_ADD_ACADEMIC )
|
||
|
||
m_SummonMonsterID = -1;
|
||
|
||
m_bAddStateEffectQueue = false;
|
||
|
||
m_bEnchantedFromBubble = false;
|
||
|
||
m_SkillStartTime = 0;
|
||
m_bFinished = false;
|
||
m_bIsPrefixTriggerSkill = false;
|
||
m_iNeedJobClassID = 0;
|
||
m_iNowLevelSkillPoint = 0;
|
||
|
||
memset (m_iOriginalNeedMP, 0x00, sizeof(m_iOriginalNeedMP));
|
||
memset (m_aeNeedEquipType, 0x00, sizeof(m_aeNeedEquipType));
|
||
|
||
#if defined(PRE_FIX_64312)
|
||
m_isAppliedSummonMonsterEnchantSkill = false;
|
||
m_bIsSummonMonsterSkill = false;
|
||
#endif // PRE_FIX_64312
|
||
|
||
#if defined(PRE_ADD_TOTAL_LEVEL_SKILL)
|
||
m_fDeltaGlobalCoolTime = 0.0f;
|
||
#endif // PRE_ADD_TOTAL_LEVEL_SKILL
|
||
}
|
||
|
||
CDnSkill::~CDnSkill(void)
|
||
{
|
||
for( int iSelectedLevelData = PVE; iSelectedLevelData < NUM_SKILLLEVEL_APPLY_TYPE; ++iSelectedLevelData )
|
||
{
|
||
SAFE_DELETE_PVEC( m_vlpUsableCheckers[ iSelectedLevelData ] );
|
||
}
|
||
|
||
for( int iSelectedLevelData = PVE; iSelectedLevelData < NUM_SKILLLEVEL_APPLY_TYPE; ++iSelectedLevelData )
|
||
{
|
||
SAFE_DELETE_PVEC( m_vlpProcessors[ iSelectedLevelData ] );
|
||
}
|
||
|
||
for( int iSelectedLevelData = PVE; iSelectedLevelData < NUM_SKILLLEVEL_APPLY_TYPE; ++iSelectedLevelData )
|
||
{
|
||
SAFE_DELETE_PVEC( m_vlpProcessorBackup[ iSelectedLevelData ] );
|
||
}
|
||
|
||
#if defined(PRE_FIX_66175)
|
||
for( int iSelectedLevelData = PVE; iSelectedLevelData < NUM_SKILLLEVEL_APPLY_TYPE; ++iSelectedLevelData )
|
||
{
|
||
SAFE_DELETE_PVEC( m_vlUsableCheckersBackup[ iSelectedLevelData ] );
|
||
}
|
||
#endif // PRE_FIX_66175
|
||
}
|
||
|
||
|
||
|
||
void CDnSkill::SetHasActor( DnActorHandle hActor )
|
||
{
|
||
_ASSERT( hActor && "CDnSkill::SetHasActor() 액터 핸들이 NULL 임" );
|
||
|
||
m_hActor = hActor;
|
||
|
||
for( int iSelectedLevelData = PVE; iSelectedLevelData < NUM_SKILLLEVEL_APPLY_TYPE; ++iSelectedLevelData )
|
||
{
|
||
int iNumChecker = (int)m_vlpUsableCheckers[ iSelectedLevelData ].size();
|
||
for( int iChecker = 0; iChecker < iNumChecker; ++iChecker )
|
||
{
|
||
IDnSkillUsableChecker* pChecker = m_vlpUsableCheckers[ iSelectedLevelData ].at( iChecker );
|
||
pChecker->SetHasActor( hActor );
|
||
}
|
||
}
|
||
|
||
for( int iSelectedLevelData = PVE; iSelectedLevelData < NUM_SKILLLEVEL_APPLY_TYPE; ++iSelectedLevelData )
|
||
{
|
||
int iNumProcessor = (int)m_vlpProcessors[ iSelectedLevelData ].size();
|
||
for( int iProcessor = 0; iProcessor < iNumProcessor; ++iProcessor )
|
||
{
|
||
IDnSkillProcessor* pProcessor = m_vlpProcessors[ iSelectedLevelData ].at( iProcessor );
|
||
pProcessor->SetHasActor( hActor );
|
||
pProcessor->SetParentSkill( GetMySmartPtr() );
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
DnSkillHandle CDnSkill::CreateSkill( DnActorHandle hActor, int iSkillTableID, int iLevel )
|
||
{
|
||
CDnSkill* pNewSkill = NULL;
|
||
|
||
// 스킬 발동 조건, 발동 프로세서들을 달아준다.
|
||
// 각각 5개씩 있고 파라메터는 전부 합쳐 10개임. 변경될 가능성도 있다.
|
||
pNewSkill = new CDnSkill( hActor );
|
||
|
||
bool bResult = pNewSkill->Initialize( iSkillTableID, iLevel );
|
||
if( false == bResult )
|
||
{
|
||
delete pNewSkill;
|
||
return CDnSkill::Identity();
|
||
}
|
||
|
||
if( hActor && hActor->IsPlayerActor() )
|
||
{
|
||
CDnPlayerActor* pPlayerActor = static_cast<CDnPlayerActor*>(hActor.GetPointer());
|
||
pNewSkill->RegisterObserver( pPlayerActor->GetBubbleSystem() );
|
||
}
|
||
|
||
return pNewSkill->GetMySmartPtr();
|
||
}
|
||
|
||
#ifdef PRE_FIX_GAMESERVER_OPTIMIZE
|
||
bool CDnSkill::_LoadMonsterSkillLevelData( int iSkillTableID, int iLevel, int iSkillLevelDataApplyType )
|
||
{
|
||
DNTableFileFormat* pSkillTable = GetDNTable( CDnTableDB::TSKILL );
|
||
DNTableFileFormat* pSkillLevelTable = GetDNTable( CDnTableDB::TSKILLLEVEL );
|
||
|
||
vector<int> vlSkillLevelList;
|
||
if( pSkillLevelTable->GetItemIDListFromField( "_SkillIndex", iSkillTableID, vlSkillLevelList ) <= 0 )
|
||
return false;
|
||
|
||
if( !pSkillTable->IsExistItem( iSkillTableID) )
|
||
return false;
|
||
|
||
// pve, pvp 대상인지 확인하여 걸러냄.
|
||
vector<int>::iterator iterLevelList = vlSkillLevelList.begin();
|
||
for( iterLevelList; iterLevelList != vlSkillLevelList.end(); )
|
||
{
|
||
int iSkillLevelTableID = *iterLevelList;
|
||
int iApplyType = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_ApplyType" )->GetInteger();
|
||
if( iApplyType != iSkillLevelDataApplyType )
|
||
iterLevelList = vlSkillLevelList.erase( iterLevelList );
|
||
else
|
||
++iterLevelList;
|
||
}
|
||
|
||
// 해당 대상의 데이터가 없는 경우엔 그냥 아무것도 안하고 리턴하면 된다.
|
||
if( vlSkillLevelList.empty() )
|
||
return true;
|
||
|
||
int iSkillLevelTableID = -1;
|
||
for( int i = 0; i < (int)vlSkillLevelList.size(); ++i )
|
||
{
|
||
int iNowLevel = pSkillLevelTable->GetFieldFromLablePtr( vlSkillLevelList.at(i), "_SkillLevel" )->GetInteger();
|
||
if( iNowLevel == iLevel )
|
||
{
|
||
iSkillLevelTableID = vlSkillLevelList.at( i );
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( -1 == iSkillLevelTableID )
|
||
return false;
|
||
|
||
char caLabel[ 32 ];
|
||
int iCheckerParamOffset = 0;
|
||
int iProcessorParamOffset = 0;
|
||
for( int i = 0; i < MAX_PROCESSOR_COUNT; ++i )
|
||
{
|
||
// 발동조건 객체 이름을 찾는다. 파라메터 필드가 비어있으면 생성 함수들에서 NULL 리턴됨
|
||
sprintf_s( caLabel, "_UsableChecker%d", i + 1 );
|
||
int iUsableChecker = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLabel )->GetInteger();
|
||
|
||
sprintf_s( caLabel, "_Processor%d", i + 1 );
|
||
int iProcessor = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLabel )->GetInteger();
|
||
|
||
int iOffsetCheck = iCheckerParamOffset;
|
||
IDnSkillUsableChecker* pUsableChecker = IDnSkillUsableChecker::Create( m_hActor, iUsableChecker, iSkillLevelTableID, &iCheckerParamOffset );
|
||
|
||
if( NULL != pUsableChecker )
|
||
{
|
||
if( (iCheckerParamOffset - iOffsetCheck) != pUsableChecker->GetNumArgument() )
|
||
{
|
||
OutputDebug( "[SkillLevelTable Error!] %d 의 파라메터 개수가 잘못되었습니다.\n", iSkillLevelTableID );
|
||
_ASSERT( !"스킬 레벨 테이블 파라메터 잘못됨. OutputDebug 출력 확인!" );
|
||
}
|
||
|
||
this->AddUsableCheckers( pUsableChecker, iSkillLevelDataApplyType );
|
||
}
|
||
|
||
iOffsetCheck = iProcessorParamOffset;
|
||
IDnSkillProcessor* pSkillProcessor = IDnSkillProcessor::Create( m_hActor, iProcessor, iSkillLevelTableID, &iProcessorParamOffset, this->GetUseActionNames() );
|
||
|
||
if( NULL != pSkillProcessor )
|
||
{
|
||
if( (iProcessorParamOffset - iOffsetCheck) != pSkillProcessor->GetNumArgument() )
|
||
{
|
||
OutputDebug( "[SkillLevelTable Error!] %d 의 파라메터 개수가 잘못되었습니다.\n", iSkillLevelTableID );
|
||
_ASSERT( !"스킬 레벨 테이블 파라메터 잘못됨. OutputDebug 출력 확인!" );
|
||
}
|
||
|
||
this->AddProcessor( pSkillProcessor, iSkillLevelDataApplyType );
|
||
}
|
||
}
|
||
|
||
// skill table
|
||
m_strStaticName = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_StaticName" )->GetString();
|
||
|
||
char caLable[ 64 ];
|
||
ZeroMemory( caLable, sizeof(caLable) );
|
||
for( int i = 0; i < 2; ++i )
|
||
{
|
||
sprintf_s( caLable, "_NeedWeaponType%d", i+1 );
|
||
int iEquipType = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLable )->GetInteger();
|
||
if( -1 != iEquipType )
|
||
m_aeNeedEquipType[ i ] = (CDnWeapon::EquipTypeEnum)iEquipType;
|
||
else
|
||
m_aeNeedEquipType[ i ] = CDnWeapon::EquipTypeEnum_Amount;
|
||
}
|
||
|
||
// 스킬 테이블의 최대 레벨은 신뢰할 수 없다. -_-
|
||
// 실제 갯수로 업데이트.
|
||
if( 0 == m_iMaxLevel )
|
||
{
|
||
m_iMaxLevel = (int)vlSkillLevelList.size();
|
||
}
|
||
else
|
||
{
|
||
_ASSERT( m_iMaxLevel == (int)vlSkillLevelList.size() );
|
||
}
|
||
|
||
m_eSkillType = (SkillTypeEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_SkillType" )->GetInteger();
|
||
m_eDurationType = (DurationTypeEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_DurationType" )->GetInteger();
|
||
m_eTargetType = (TargetTypeEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_TargetType" )->GetInteger();
|
||
|
||
m_iDissolvable = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_Dissolvable" )->GetInteger();
|
||
m_iDuplicateCount = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_EffectAmassCount" )->GetInteger();
|
||
m_iSkillDuplicateMethod = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_SkillDuplicate" )->GetInteger();
|
||
m_iEffectDuplicateMethod = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_EffectDuplicate" )->GetInteger();
|
||
m_eElement = (CDnState::ElementEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_Element" )->GetInteger();
|
||
m_iNeedJobClassID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_NeedJob" )->GetInteger();
|
||
if( (CDnState::ElementEnum)-1 == m_eElement )
|
||
m_eElement = CDnState::ElementEnum_Amount;
|
||
|
||
// skill level table
|
||
m_iSkillLevelID = iSkillLevelTableID;
|
||
m_iLevel = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_SkillLevel" )->GetInteger();
|
||
m_iNowLevelSkillPoint = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_NeedSkillPoint" )->GetInteger();
|
||
|
||
#if defined(PRE_FIX_NEXTSKILLINFO)
|
||
SKILL_LEVEL_INFO* pTabelInfo = g_pDataManager->GetSkillLevelTableIDList(iSkillTableID, iSkillLevelDataApplyType);
|
||
int nextSkillLevel = m_iLevel + 1;
|
||
|
||
if( m_iLevel < m_iMaxLevel )
|
||
{
|
||
int nextLevelTableID = -1;
|
||
SKILL_LEVEL_TABLE_IDS::iterator findIter = pTabelInfo->_SkillLevelTableIDs.find(nextSkillLevel);
|
||
if (findIter != pTabelInfo->_SkillLevelTableIDs.end())
|
||
nextLevelTableID = findIter->second;
|
||
|
||
m_iNextLevelSkillPoint = pSkillLevelTable->GetFieldFromLablePtr( nextLevelTableID, "_NeedSkillPoint" )->GetInteger();
|
||
}
|
||
else
|
||
m_iNextLevelSkillPoint = 0;
|
||
|
||
#else
|
||
if( m_iLevel < m_iMaxLevel )
|
||
m_iNextLevelSkillPoint = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID+1, "_NeedSkillPoint" )->GetInteger();
|
||
else
|
||
m_iNextLevelSkillPoint = 0;
|
||
#endif // PRE_FIX_NEXTSKILLINFO
|
||
|
||
m_iIncreaseRange[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_AddRange" )->GetInteger();
|
||
|
||
m_iAdditionalThreat = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_AddThreat" )->GetInteger();
|
||
|
||
m_iCPScore = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_CPScore" )->GetInteger();
|
||
m_fStartSuperArmor = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StartSuperArmor" )->GetFloat();
|
||
m_bStartCanHit = (pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StartCanHit" )->GetInteger() == 1) ? true : false;
|
||
|
||
// 상태 효과 정보 로딩
|
||
StateEffectStruct StateEffect;
|
||
for( int i = 0; i < MAX_STATE_EFFECT_COUNT; ++i )
|
||
{
|
||
sprintf_s( caLable, "_EffectClass%d", i + 1 );
|
||
StateEffect.nID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLable )->GetInteger();
|
||
|
||
if( StateEffect.nID < 1 )
|
||
continue;
|
||
|
||
sprintf_s( caLable, "_EffectClass%dApplyType", i + 1 );
|
||
int iApplyType = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLable )->GetInteger();
|
||
// 모두 적용임. 타겟만 다르게 해서 똑같은 상태효과 2개를 추가해준다.
|
||
// 하지만 강화 패시브로 사용되는 스킬은 2개로 하지 않고 그냥 생성. 다른 스킬을 강화시키는 데이터 역할만 수행하기 때문.
|
||
bool bApplyAll = (StateEffectApplyType::ApplyAll == iApplyType) && (SkillTypeEnum::EnchantPassive != m_eSkillType);
|
||
|
||
if( bApplyAll )
|
||
StateEffect.ApplyType = StateEffectApplyType::ApplySelf;
|
||
else
|
||
StateEffect.ApplyType = (StateEffectApplyType)iApplyType;
|
||
|
||
sprintf_s( caLable, "_EffectClassValue%d", i + 1 );
|
||
StateEffect.szValue = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, caLable )->GetString();
|
||
|
||
sprintf_s( caLable, "_EffectClassValue%dDuration", i + 1 );
|
||
StateEffect.nDurationTime = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, caLable )->GetInteger();
|
||
|
||
m_vlStateEffectList[ iSkillLevelDataApplyType ].push_back( StateEffect );
|
||
|
||
// 모두 적용이면 타겟으로 바꿔서 똑같이 한 번 더 넣어줌.
|
||
if( bApplyAll )
|
||
{
|
||
StateEffect.ApplyType = StateEffectApplyType::ApplyTarget;
|
||
m_vlStateEffectList[ iSkillLevelDataApplyType ].push_back( StateEffect );
|
||
}
|
||
}
|
||
|
||
SkillInfo& MySkillInfo = m_SkillInfo[ iSkillLevelDataApplyType ];
|
||
MySkillInfo.iSkillID = m_iSkillID;
|
||
MySkillInfo.iSkillLevelID = m_iSkillLevelID;
|
||
MySkillInfo.iLevel = m_iLevel;
|
||
MySkillInfo.iSkillDuplicateMethod = m_iSkillDuplicateMethod;
|
||
MySkillInfo.iDuplicateCount = m_iDuplicateCount;
|
||
|
||
MySkillInfo.eSkillType = m_eSkillType;
|
||
MySkillInfo.eDurationType = m_eDurationType;
|
||
MySkillInfo.eTargetType = m_eTargetType;
|
||
MySkillInfo.eApplyType = StateEffect.ApplyType;
|
||
MySkillInfo.iDissolvable = m_iDissolvable;
|
||
MySkillInfo.eSkillElement = m_eElement;
|
||
MySkillInfo.hSkillUser = m_hActor; // Note: 액터가 항상 유효한 것은 아님
|
||
if( m_hActor )
|
||
MySkillInfo.iSkillUserTeam = m_hActor->GetTeam();
|
||
|
||
if( m_hActor && _tcslen(m_hActor->GetName()) > 0 )
|
||
MySkillInfo.strUserName = m_hActor->GetName();
|
||
|
||
MySkillInfo.szEffectOutputIDs = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StateEffectTableID" )->GetString();
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CDnSkill::InitializeMonsterSkill( int iSkillTableID, int iLevel )
|
||
{
|
||
m_iSkillID = iSkillTableID;
|
||
|
||
// 각 모드별로 데이터 로드. 먼저 PVP 를 읽는다.
|
||
// PVE 는 디폴트 값이기 때문에 모드별로 나뉘어지는 값이 아니면 디폴트 값으로 채워지게 된다.
|
||
|
||
// 몬스터 스킬 생성 함수이므로 PVE 만 호출.
|
||
if( false == _LoadSkillLevelData( iSkillTableID, iLevel, PVP ) )
|
||
return false;
|
||
|
||
if( false == _LoadSkillLevelData( iSkillTableID, iLevel, PVE ) )
|
||
return false;
|
||
|
||
int iNumProcessor = (int)m_vlpProcessors[ PVE ].size();
|
||
for( int iProcessor = 0; iProcessor < iNumProcessor; ++iProcessor )
|
||
{
|
||
IDnSkillProcessor* pProcessor = m_vlpProcessors[ PVE ].at( iProcessor );
|
||
|
||
// 사용하는 액션이 있으면 외부에서 조회용으로 데이터 채워놓음
|
||
if( pProcessor->GetType() == IDnSkillProcessor::PLAY_ANI )
|
||
m_setUseActionNames.insert( static_cast<CDnPlayAniProcess*>(pProcessor)->GetActionName() );
|
||
else
|
||
if( pProcessor->GetType() == IDnSkillProcessor::PARTIAL_PLAY_ANI )
|
||
{
|
||
CDnPartialPlayProcessor* pPartialPlayAni = static_cast<CDnPartialPlayProcessor*>(pProcessor);
|
||
m_setUseActionNames.insert( pPartialPlayAni->GetStartActionName() );
|
||
m_setUseActionNames.insert( pPartialPlayAni->GetLoopActionName() );
|
||
m_setUseActionNames.insert( pPartialPlayAni->GetEndActionName() );
|
||
}
|
||
}
|
||
|
||
// 초기화 했을 때는 pve 모드가 디폴트임.
|
||
m_iSelectedSkillLevelDataApplyType = PVE;
|
||
|
||
return true;
|
||
}
|
||
|
||
DnSkillHandle CDnSkill::CreateMonsterSkill( DnActorHandle hActor, int iSkillTableID, int iLevel )
|
||
{
|
||
if( hActor )
|
||
{
|
||
CDnSkill* pNewSkill = pNewSkill = new CDnSkill( hActor );
|
||
if( pNewSkill )
|
||
{
|
||
bool bResult = pNewSkill->InitializeMonsterSkill( iSkillTableID, iLevel );
|
||
if( false == bResult )
|
||
{
|
||
SAFE_DELETE( pNewSkill );
|
||
return CDnSkill::Identity();
|
||
}
|
||
|
||
if( hActor->IsPlayerActor() )
|
||
{
|
||
CDnPlayerActor* pPlayerActor = static_cast<CDnPlayerActor*>(hActor.GetPointer());
|
||
pNewSkill->RegisterObserver( pPlayerActor->GetBubbleSystem() );
|
||
}
|
||
|
||
return pNewSkill->GetMySmartPtr();
|
||
}
|
||
else
|
||
{
|
||
SAFE_DELETE( pNewSkill );
|
||
return CDnSkill::Identity();
|
||
}
|
||
}
|
||
|
||
return CDnSkill::Identity();
|
||
}
|
||
#endif // #ifdef PRE_FIX_GAMESERVER_OPTIMIZE
|
||
|
||
void CDnSkill::CreateSkillInfo( int nSkillID, int nSkillLevel, CDnSkill::SkillInfo & sSkillInfo, std::vector<CDnSkill::StateEffectStruct> & vecSkillEffect, bool bUseBattleGround/* = false*/ )
|
||
{
|
||
if( nSkillID == 0 || nSkillLevel == 0 )
|
||
return;
|
||
|
||
DNTableFileFormat* pSkillTable = NULL;
|
||
DNTableFileFormat* pSkillLevelTable = NULL;
|
||
if (bUseBattleGround)
|
||
{
|
||
pSkillTable = GetDNTable( CDnTableDB::TBATTLEGROUNDSKILL );
|
||
pSkillLevelTable = GetDNTable( CDnTableDB::TBATTLEGROUNDSKILLLEVEL );
|
||
}
|
||
else
|
||
{
|
||
pSkillTable = GetDNTable( CDnTableDB::TSKILL );
|
||
pSkillLevelTable = GetDNTable( CDnTableDB::TSKILLLEVEL );
|
||
}
|
||
|
||
if (pSkillLevelTable == NULL || pSkillTable == NULL)
|
||
{
|
||
_DANGER_POINT();
|
||
return;
|
||
}
|
||
std::vector<int> vlSkillLevelList;
|
||
if( pSkillLevelTable->GetItemIDListFromField( "_SkillIndex", nSkillID, vlSkillLevelList ) <= 0 )
|
||
return;
|
||
|
||
int iSkillLevelTableID = -1;
|
||
for( int i = 0; i < (int)vlSkillLevelList.size(); ++i )
|
||
{
|
||
int iNowLevel = pSkillLevelTable->GetFieldFromLablePtr( vlSkillLevelList.at(i), "_SkillLevel" )->GetInteger();
|
||
if( iNowLevel == nSkillLevel )
|
||
{
|
||
iSkillLevelTableID = vlSkillLevelList.at( i );
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( -1 == iSkillLevelTableID )
|
||
return;
|
||
|
||
sSkillInfo.iSkillID = nSkillID;
|
||
sSkillInfo.iSkillLevelID = iSkillLevelTableID;
|
||
#ifdef PRE_FIX_SYNC_ENCHANT_SKILL
|
||
sSkillInfo.iAppliedEnchantSkillID = 0;
|
||
#endif
|
||
sSkillInfo.iLevel = nSkillLevel;
|
||
sSkillInfo.eDurationType = (CDnSkill::DurationTypeEnum)pSkillTable->GetFieldFromLablePtr( nSkillID, "_DurationType" )->GetInteger();
|
||
sSkillInfo.eTargetType = (CDnSkill::TargetTypeEnum)pSkillTable->GetFieldFromLablePtr( nSkillID, "_TargetType" )->GetInteger();
|
||
sSkillInfo.iSkillDuplicateMethod = pSkillTable->GetFieldFromLablePtr( nSkillID, "_SkillDuplicate" )->GetInteger();
|
||
sSkillInfo.iDuplicateCount = pSkillTable->GetFieldFromLablePtr( nSkillID, "_EffectAmassCount" )->GetInteger();
|
||
sSkillInfo.iDissolvable = pSkillTable->GetFieldFromLablePtr( nSkillID, "_Dissolvable" )->GetInteger();
|
||
sSkillInfo.szEffectOutputIDToClient = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StateEffectTableID" )->GetString();
|
||
|
||
sSkillInfo.bFromBuffProp = true;
|
||
|
||
// 상태 효과 정보 로딩
|
||
CDnSkill::StateEffectStruct StateEffect;
|
||
char caLable[ 64 ];
|
||
ZeroMemory( caLable, sizeof(caLable) );
|
||
for( int i = 0; i < MAX_STATE_EFFECT_COUNT; ++i )
|
||
{
|
||
sprintf_s( caLable, "_EffectClass%d", i + 1 );
|
||
StateEffect.nID = pSkillTable->GetFieldFromLablePtr( nSkillID, caLable )->GetInteger();
|
||
|
||
if( StateEffect.nID < 1 )
|
||
continue;
|
||
|
||
sprintf_s( caLable, "_EffectClass%dApplyType", i + 1 );
|
||
StateEffect.ApplyType = (CDnSkill::StateEffectApplyType)pSkillTable->GetFieldFromLablePtr( nSkillID, caLable )->GetInteger();
|
||
|
||
sprintf_s( caLable, "_EffectClassValue%d", i + 1 );
|
||
StateEffect.szValue = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, caLable )->GetString();
|
||
|
||
sprintf_s( caLable, "_EffectClassValue%dDuration", i + 1 );
|
||
StateEffect.nDurationTime = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, caLable )->GetInteger();
|
||
|
||
vecSkillEffect.push_back( StateEffect );
|
||
}
|
||
}
|
||
|
||
void CDnSkill::CreateBattleGroundSkillInfo( int nSkillID, int nSkillLevel, CDnSkill::SkillInfo & sSkillInfo, std::vector<CDnSkill::StateEffectStruct> & vecSkillEffect )
|
||
{
|
||
CreateSkillInfo(nSkillID, nSkillLevel, sSkillInfo, vecSkillEffect, true);
|
||
}
|
||
|
||
bool CDnSkill::_LoadSkillLevelData( int iSkillTableID, int iLevel, int iSkillLevelDataApplyType )
|
||
{
|
||
DNTableFileFormat* pSkillTable = GetDNTable( CDnTableDB::TSKILL );
|
||
DNTableFileFormat* pSkillLevelTable = GetDNTable( CDnTableDB::TSKILLLEVEL );
|
||
|
||
vector<int> vlSkillLevelList;
|
||
if( pSkillLevelTable->GetItemIDListFromField( "_SkillIndex", iSkillTableID, vlSkillLevelList ) <= 0 )
|
||
return false;
|
||
|
||
if( !pSkillTable->IsExistItem( iSkillTableID) )
|
||
return false;
|
||
|
||
// pve, pvp 대상인지 확인하여 걸러냄.
|
||
vector<int>::iterator iterLevelList = vlSkillLevelList.begin();
|
||
for( iterLevelList; iterLevelList != vlSkillLevelList.end(); )
|
||
{
|
||
int iSkillLevelTableID = *iterLevelList;
|
||
int iApplyType = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_ApplyType" )->GetInteger();
|
||
if( iApplyType != iSkillLevelDataApplyType )
|
||
iterLevelList = vlSkillLevelList.erase( iterLevelList );
|
||
else
|
||
++iterLevelList;
|
||
}
|
||
|
||
// 해당 대상의 데이터가 없는 경우엔 그냥 아무것도 안하고 리턴하면 된다.
|
||
if( vlSkillLevelList.empty() )
|
||
return true;
|
||
|
||
int iSkillLevelTableID = -1;
|
||
for( int i = 0; i < (int)vlSkillLevelList.size(); ++i )
|
||
{
|
||
int iNowLevel = pSkillLevelTable->GetFieldFromLablePtr( vlSkillLevelList.at(i), "_SkillLevel" )->GetInteger();
|
||
if( iNowLevel == iLevel )
|
||
{
|
||
iSkillLevelTableID = vlSkillLevelList.at( i );
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( -1 == iSkillLevelTableID )
|
||
return false;
|
||
|
||
#if defined(PRE_FIX_NEXTSKILLINFO)
|
||
//NextLevel이 연속으로 있지 않을 수 있다.. 그래서 여기서 다음 레벨 데이타 테이블 ID를 찾아 놓는다.
|
||
int iMinSkillLevelTableID = -1;
|
||
int iNextSkillLevelTableID = -1;
|
||
|
||
SKILL_LEVEL_INFO* pTableInfo = g_pDataManager->GetSkillLevelTableIDList(iSkillLevelTableID, iSkillLevelDataApplyType);
|
||
SKILL_LEVEL_TABLE_IDS::iterator findIter = pTableInfo->_SkillLevelTableIDs.find(pTableInfo->_MinLevel);
|
||
if (findIter != pTableInfo->_SkillLevelTableIDs.end())
|
||
iMinSkillLevelTableID = findIter->second;
|
||
|
||
findIter = pTableInfo->_SkillLevelTableIDs.find(iLevel + 1);
|
||
if (findIter != pTableInfo->_SkillLevelTableIDs.end())
|
||
iNextSkillLevelTableID = findIter->second;
|
||
|
||
#endif // PRE_FIX_NEXTSKILLINFO
|
||
|
||
char caLabel[ 32 ];
|
||
int iCheckerParamOffset = 0;
|
||
int iProcessorParamOffset = 0;
|
||
for( int i = 0; i < MAX_PROCESSOR_COUNT; ++i )
|
||
{
|
||
// 발동조건 객체 이름을 찾는다. 파라메터 필드가 비어있으면 생성 함수들에서 NULL 리턴됨
|
||
sprintf_s( caLabel, "_UsableChecker%d", i + 1 );
|
||
int iUsableChecker = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLabel )->GetInteger();
|
||
|
||
sprintf_s( caLabel, "_Processor%d", i + 1 );
|
||
int iProcessor = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLabel )->GetInteger();
|
||
|
||
int iOffsetCheck = iCheckerParamOffset;
|
||
IDnSkillUsableChecker* pUsableChecker = IDnSkillUsableChecker::Create( m_hActor, iUsableChecker, iSkillLevelTableID, &iCheckerParamOffset );
|
||
|
||
if( NULL != pUsableChecker )
|
||
{
|
||
if( (iCheckerParamOffset - iOffsetCheck) != pUsableChecker->GetNumArgument() )
|
||
{
|
||
OutputDebug( "[SkillLevelTable Error!] %d 의 파라메터 개수가 잘못되었습니다.\n", iSkillLevelTableID );
|
||
_ASSERT( !"스킬 레벨 테이블 파라메터 잘못됨. OutputDebug 출력 확인!" );
|
||
}
|
||
|
||
this->AddUsableCheckers( pUsableChecker, iSkillLevelDataApplyType );
|
||
}
|
||
|
||
iOffsetCheck = iProcessorParamOffset;
|
||
IDnSkillProcessor* pSkillProcessor = IDnSkillProcessor::Create( m_hActor, iProcessor, iSkillLevelTableID, &iProcessorParamOffset, this->GetUseActionNames() );
|
||
|
||
if( NULL != pSkillProcessor )
|
||
{
|
||
if( (iProcessorParamOffset - iOffsetCheck) != pSkillProcessor->GetNumArgument() )
|
||
{
|
||
OutputDebug( "[SkillLevelTable Error!] %d 의 파라메터 개수가 잘못되었습니다.\n", iSkillLevelTableID );
|
||
_ASSERT( !"스킬 레벨 테이블 파라메터 잘못됨. OutputDebug 출력 확인!" );
|
||
}
|
||
|
||
this->AddProcessor( pSkillProcessor, iSkillLevelDataApplyType );
|
||
}
|
||
}
|
||
|
||
// skill table
|
||
m_strStaticName = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_StaticName" )->GetString();
|
||
|
||
char caLable[ 64 ];
|
||
ZeroMemory( caLable, sizeof(caLable) );
|
||
for( int i = 0; i < 2; ++i )
|
||
{
|
||
sprintf_s( caLable, "_NeedWeaponType%d", i+1 );
|
||
int iEquipType = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLable )->GetInteger();
|
||
if( -1 != iEquipType )
|
||
m_aeNeedEquipType[ i ] = (CDnWeapon::EquipTypeEnum)iEquipType;
|
||
else
|
||
m_aeNeedEquipType[ i ] = CDnWeapon::EquipTypeEnum_Amount;
|
||
}
|
||
|
||
// 스킬 테이블의 최대 레벨은 신뢰할 수 없다. -_-
|
||
// 실제 갯수로 업데이트.
|
||
if( 0 == m_iMaxLevel )
|
||
{
|
||
m_iMaxLevel = (int)vlSkillLevelList.size();
|
||
}
|
||
else
|
||
{
|
||
_ASSERT( m_iMaxLevel == (int)vlSkillLevelList.size() );
|
||
}
|
||
|
||
m_eSkillType = (SkillTypeEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_SkillType" )->GetInteger();
|
||
m_eDurationType = (DurationTypeEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_DurationType" )->GetInteger();
|
||
m_eTargetType = (TargetTypeEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_TargetType" )->GetInteger();
|
||
|
||
m_iDissolvable = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_Dissolvable" )->GetInteger();
|
||
m_iDuplicateCount = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_EffectAmassCount" )->GetInteger();
|
||
m_iSkillDuplicateMethod = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_SkillDuplicate" )->GetInteger();
|
||
m_iEffectDuplicateMethod = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_EffectDuplicate" )->GetInteger();
|
||
m_eElement = (CDnState::ElementEnum)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_Element" )->GetInteger();
|
||
m_iNeedJobClassID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_NeedJob" )->GetInteger();
|
||
if( (CDnState::ElementEnum)-1 == m_eElement )
|
||
m_eElement = CDnState::ElementEnum_Amount;
|
||
|
||
m_iExclusiveID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_DuplicatedSkillType" )->GetInteger();
|
||
m_iBaseSkillID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_BaseSkillID" )->GetInteger();
|
||
|
||
m_iGlobalSkillGroupID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_GlobalSkillGroup" )->GetInteger();
|
||
|
||
float fGlobalCoolTime = 0.0f;
|
||
if( PVE == iSkillLevelDataApplyType )
|
||
fGlobalCoolTime = (float)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_GlobalCoolTimePvE" )->GetInteger() / 1000.0f;
|
||
else
|
||
if( PVP == iSkillLevelDataApplyType )
|
||
fGlobalCoolTime = (float)pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_GlobalCoolTimePvP" )->GetInteger() / 1000.0f;
|
||
|
||
m_afGlobalCoolTime[ iSkillLevelDataApplyType ] = fGlobalCoolTime;
|
||
|
||
// skill level table
|
||
m_iSkillLevelID = iSkillLevelTableID;
|
||
m_iLevel = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_SkillLevel" )->GetInteger();
|
||
m_iNowLevelSkillPoint = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_NeedSkillPoint" )->GetInteger();
|
||
if( m_iLevel < m_iMaxLevel )
|
||
#if defined(PRE_FIX_NEXTSKILLINFO)
|
||
m_iNextLevelSkillPoint = pSkillLevelTable->GetFieldFromLablePtr( iNextSkillLevelTableID, "_NeedSkillPoint" )->GetInteger();
|
||
#else
|
||
m_iNextLevelSkillPoint = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID+1, "_NeedSkillPoint" )->GetInteger();
|
||
#endif // PRE_FIX_NEXTSKILLINFO
|
||
else
|
||
m_iNextLevelSkillPoint = 0;
|
||
|
||
m_iNeedItemID[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_NeedItem" )->GetInteger();
|
||
m_iNeedItemDecreaseCount[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_NeedItemDecreaseCount" )->GetInteger();
|
||
m_iIncreaseRange[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_AddRange" )->GetInteger();
|
||
m_iDecreaseHP[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_DecreaseHP" )->GetInteger();
|
||
m_iDecreaseMP[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_DecreaseSP" )->GetInteger();
|
||
m_iLevelLimit = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_LevelLimit" )->GetInteger();
|
||
m_fDelayTime[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_DelayTime" )->GetInteger() / 1000.f;
|
||
|
||
// 만약 글로벌 스킬 그룹이 설정되어있다면 스킬 쿨타임을 글로벌 쿨타임으로 대체 시켜준다.
|
||
if( 0 < m_iGlobalSkillGroupID )
|
||
m_fDelayTime[ iSkillLevelDataApplyType ] = m_afGlobalCoolTime[ iSkillLevelDataApplyType ];
|
||
|
||
m_fOriginalDelayTime[ iSkillLevelDataApplyType ] = m_fDelayTime[ iSkillLevelDataApplyType ];
|
||
m_iAdditionalThreat = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_AddThreat" )->GetInteger();
|
||
|
||
m_fHPConsumeType[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_HPConsumeType" )->GetFloat();
|
||
m_fMPConsumeType[ iSkillLevelDataApplyType ] = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_SPConsumeType" )->GetFloat();
|
||
m_iCPScore = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_CPScore" )->GetInteger();
|
||
m_fStartSuperArmor = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StartSuperArmor" )->GetFloat();
|
||
m_bStartCanHit = (pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StartCanHit" )->GetInteger() == 1) ? true : false;
|
||
|
||
// 상태 효과 정보 로딩
|
||
StateEffectStruct StateEffect;
|
||
for( int i = 0; i < MAX_STATE_EFFECT_COUNT; ++i )
|
||
{
|
||
sprintf_s( caLable, "_EffectClass%d", i + 1 );
|
||
StateEffect.nID = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLable )->GetInteger();
|
||
|
||
if( StateEffect.nID < 1 )
|
||
continue;
|
||
|
||
sprintf_s( caLable, "_EffectClass%dApplyType", i + 1 );
|
||
int iApplyType = pSkillTable->GetFieldFromLablePtr( iSkillTableID, caLable )->GetInteger();
|
||
// 모두 적용임. 타겟만 다르게 해서 똑같은 상태효과 2개를 추가해준다.
|
||
// 하지만 강화 패시브로 사용되는 스킬은 2개로 하지 않고 그냥 생성. 다른 스킬을 강화시키는 데이터 역할만 수행하기 때문.
|
||
bool bApplyAll = (StateEffectApplyType::ApplyAll == iApplyType) && (SkillTypeEnum::EnchantPassive != m_eSkillType);
|
||
|
||
if( bApplyAll )
|
||
{
|
||
StateEffect.ApplyType = StateEffectApplyType::ApplySelf;
|
||
StateEffect.bApplyAllPair = true;
|
||
}
|
||
else
|
||
StateEffect.ApplyType = (StateEffectApplyType)iApplyType;
|
||
|
||
sprintf_s( caLable, "_EffectClassValue%d", i + 1 );
|
||
StateEffect.szValue = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, caLable )->GetString();
|
||
|
||
sprintf_s( caLable, "_EffectClassValue%dDuration", i + 1 );
|
||
StateEffect.nDurationTime = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, caLable )->GetInteger();
|
||
|
||
m_vlStateEffectList[ iSkillLevelDataApplyType ].push_back( StateEffect );
|
||
|
||
// 모두 적용이면 타겟으로 바꿔서 똑같이 한 번 더 넣어줌.
|
||
if( bApplyAll )
|
||
{
|
||
StateEffect.ApplyType = StateEffectApplyType::ApplyTarget;
|
||
m_vlStateEffectList[ iSkillLevelDataApplyType ].push_back( StateEffect );
|
||
}
|
||
}
|
||
|
||
SkillInfo& MySkillInfo = m_SkillInfo[ iSkillLevelDataApplyType ];
|
||
MySkillInfo.iSkillID = m_iSkillID;
|
||
MySkillInfo.iSkillLevelID = m_iSkillLevelID;
|
||
MySkillInfo.iLevel = m_iLevel;
|
||
MySkillInfo.iSkillDuplicateMethod = m_iSkillDuplicateMethod;
|
||
MySkillInfo.iDuplicateCount = m_iDuplicateCount;
|
||
|
||
MySkillInfo.eSkillType = m_eSkillType;
|
||
MySkillInfo.eDurationType = m_eDurationType;
|
||
MySkillInfo.eTargetType = m_eTargetType;
|
||
MySkillInfo.eApplyType = StateEffect.ApplyType;
|
||
MySkillInfo.iDissolvable = m_iDissolvable;
|
||
MySkillInfo.eSkillElement = m_eElement;
|
||
MySkillInfo.hSkillUser = m_hActor; // Note: 액터가 항상 유효한 것은 아님
|
||
if( m_hActor )
|
||
MySkillInfo.iSkillUserTeam = m_hActor->GetTeam();
|
||
|
||
if( m_hActor && _tcslen(m_hActor->GetName()) > 0 )
|
||
MySkillInfo.strUserName = m_hActor->GetName();
|
||
|
||
MySkillInfo.szEffectOutputIDs = pSkillLevelTable->GetFieldFromLablePtr( iSkillLevelTableID, "_StateEffectTableID" )->GetString();
|
||
|
||
if( 0.0f == m_fHPConsumeType[ iSkillLevelDataApplyType ] )
|
||
{
|
||
m_iNeedHP[ iSkillLevelDataApplyType ] = m_iDecreaseHP[ iSkillLevelDataApplyType ];
|
||
}
|
||
else
|
||
{
|
||
m_iNeedHP[ iSkillLevelDataApplyType ] = int((float)m_hActor->GetMaxHP() * m_fHPConsumeType[ iSkillLevelDataApplyType ]);
|
||
}
|
||
|
||
#if defined(PRE_ADD_PREFIX_SYSTE_RENEW)
|
||
m_nPrefixSkillType = pSkillTable->GetFieldFromLablePtr( iSkillTableID, "_Group" )->GetInteger();
|
||
|
||
//스킬 정보에 접미사 스킬 그룹ID를 설정 해 놓는다..(클라이언트는 몰라도 됨?...)
|
||
SetPrefixSkillType(m_nPrefixSkillType);
|
||
#endif // PRE_ADD_PREFIX_SYSTE_RENEW
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
void CDnSkill::_OnInitialize( void )
|
||
{
|
||
// 129번 ChangeActionSet 상태효과와 DnApplySEWhenActionSetBlowEnabledProcessor 발현 타입이 있다면 ChangeActionSet 을 제외한 모든 상태효과를
|
||
// 발현타입 객체에 몰아주고 삭제. 추후에 바뀐 액션에서만 상태효과가 유효하도록 발현타입에서 컨트롤 하게 된다.
|
||
// 우선 그냥 포인터를 물려볼까..
|
||
for( int k = PVE; k < NUM_SKILLLEVEL_APPLY_TYPE; ++k )
|
||
{
|
||
CDnApplySEWhenActionSetBlowEnabledProcessor* pApplySEWhenActionSetBlowEnableProcessor =
|
||
static_cast<CDnApplySEWhenActionSetBlowEnabledProcessor*>(GetProcessor( IDnSkillProcessor::APPLY_SE_WHEN_ACTIONSET_ENABLED, k ));
|
||
if( pApplySEWhenActionSetBlowEnableProcessor )
|
||
{
|
||
// 이 발현타입이 있는데 ChangeActionSet 상태효과와 ChangeActionStr 발현타입이 없으면 오류..
|
||
bool bValid = false;
|
||
for( int i = 0; i < (int)m_vlStateEffectList[ k ].size(); ++i )
|
||
{
|
||
StateEffectStruct& StateEffect = m_vlStateEffectList[ k ].at( i );
|
||
if( STATE_BLOW::BLOW_129 == StateEffect.nID )
|
||
{
|
||
bValid = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( bValid )
|
||
{
|
||
CDnChangeActionStrProcessor* pChangeActionStrProcessor = static_cast<CDnChangeActionStrProcessor*>(GetProcessor( IDnSkillProcessor::CHANGE_ACTIONSTR, k ));
|
||
if( pChangeActionStrProcessor )
|
||
bValid = true;
|
||
else
|
||
bValid = false;
|
||
}
|
||
|
||
if( bValid )
|
||
{
|
||
for( int i = 0; i < (int)m_vlStateEffectList[ k ].size(); ++i )
|
||
{
|
||
StateEffectStruct& StateEffect = m_vlStateEffectList[ k ].at( i );
|
||
if( STATE_BLOW::BLOW_129 != StateEffect.nID )
|
||
{
|
||
pApplySEWhenActionSetBlowEnableProcessor->AddStateEffect( &StateEffect );
|
||
StateEffect.bApplyInProcessor = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
bool CDnSkill::Initialize( int iSkillTableID, int iLevel )
|
||
{
|
||
m_iSkillID = iSkillTableID;
|
||
|
||
// 각 모드별로 데이터 로드. 먼저 PVP 를 읽는다.
|
||
// PVE 는 디폴트 값이기 때문에 모드별로 나뉘어지는 값이 아니면 디폴트 값으로 채워지게 된다.
|
||
|
||
// 몬스터인 경우엔 pvp 데이터가 없으므로 함수 안에서 아무것도 안되고 리턴된다.
|
||
// 만약 플레이어인데 아무것도 없다면 잘못된 거임.
|
||
if( false == _LoadSkillLevelData( iSkillTableID, iLevel, PVP ) )
|
||
return false;
|
||
|
||
if( false == _LoadSkillLevelData( iSkillTableID, iLevel, PVE ) )
|
||
return false;
|
||
|
||
// 초기화 이후에 따로 모아놓을 정보들.
|
||
DNTableFileFormat* pSkillTable = GetDNTable( CDnTableDB::TSKILL );
|
||
|
||
RefreshDecreaseMP();
|
||
|
||
int iNumProcessor = (int)m_vlpProcessors[ PVE ].size();
|
||
for( int iProcessor = 0; iProcessor < iNumProcessor; ++iProcessor )
|
||
{
|
||
IDnSkillProcessor* pProcessor = m_vlpProcessors[ PVE ].at( iProcessor );
|
||
|
||
// 사용하는 액션이 있으면 외부에서 조회용으로 데이터 채워놓음
|
||
if( pProcessor->GetType() == IDnSkillProcessor::PLAY_ANI )
|
||
m_setUseActionNames.insert( static_cast<CDnPlayAniProcess*>(pProcessor)->GetActionName() );
|
||
else
|
||
if( pProcessor->GetType() == IDnSkillProcessor::PARTIAL_PLAY_ANI )
|
||
{
|
||
CDnPartialPlayProcessor* pPartialPlayAni = static_cast<CDnPartialPlayProcessor*>(pProcessor);
|
||
m_setUseActionNames.insert( pPartialPlayAni->GetStartActionName() );
|
||
m_setUseActionNames.insert( pPartialPlayAni->GetLoopActionName() );
|
||
m_setUseActionNames.insert( pPartialPlayAni->GetEndActionName() );
|
||
}
|
||
}
|
||
|
||
// 초기화 했을 때는 pve 모드가 디폴트임.
|
||
m_iSelectedSkillLevelDataApplyType = PVE;
|
||
|
||
_OnInitialize();
|
||
|
||
if (m_eDurationType == SummonOnOff)
|
||
OnInitializeSummonMonsterInfo();
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
bool CDnSkill::AddUsableCheckers( IDnSkillUsableChecker* pUsableChecker, int iSelectedLevelData )
|
||
{
|
||
bool bResult = false;
|
||
|
||
if( pUsableChecker )
|
||
{
|
||
m_vlpUsableCheckers[ iSelectedLevelData ].push_back( pUsableChecker );
|
||
bResult = true;
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
|
||
bool CDnSkill::AddProcessor( IDnSkillProcessor* pProcessor, int iSelectedLevelData )
|
||
{
|
||
bool bResult = false;
|
||
|
||
if( pProcessor )
|
||
{
|
||
m_vlpProcessors[ iSelectedLevelData ].push_back( pProcessor );
|
||
bResult = true;
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
|
||
bool CDnSkill::IsSatisfyWeapon( void )
|
||
{
|
||
bool bSatisfy = true;
|
||
|
||
if( (CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ 0 ]) ||
|
||
(CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ 1 ]) )
|
||
{
|
||
bSatisfy = false;
|
||
|
||
if( CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ 0 ] && CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ 1 ] )
|
||
{
|
||
if( CDnWeapon::IsSubWeapon( m_aeNeedEquipType[ 0 ] ) == CDnWeapon::IsSubWeapon( m_aeNeedEquipType[ 1 ] ) ) // 1. 둘다 주무기이거나 보조무기 인 경우 or
|
||
{
|
||
int nWeapon = CDnWeapon::IsSubWeapon( m_aeNeedEquipType[ 0 ] ) ? 1 : 0;
|
||
#ifdef _GAMESERVER
|
||
if( m_hActor->GetWeapon( nWeapon ) && m_aeNeedEquipType[ 0 ] == m_hActor->GetWeapon( nWeapon )->GetEquipType()
|
||
|| m_hActor->GetWeapon( nWeapon ) && m_aeNeedEquipType[ 1 ] == m_hActor->GetWeapon( nWeapon )->GetEquipType() )
|
||
#else // _GAMESERVER
|
||
if( m_hActor->GetWeapon( nWeapon, false ) && m_aeNeedEquipType[ 0 ] == m_hActor->GetWeapon( nWeapon, false )->GetEquipType()
|
||
|| m_hActor->GetWeapon( nWeapon, false ) && m_aeNeedEquipType[ 1 ] == m_hActor->GetWeapon( nWeapon, false )->GetEquipType() )
|
||
#endif // _GAMESERVER
|
||
bSatisfy = true;
|
||
}
|
||
else // 2. 주무기, 보조무기인 경우 and
|
||
{
|
||
if( CDnWeapon::IsSubWeapon( m_aeNeedEquipType[ 0 ] ) )
|
||
{
|
||
#ifdef _GAMESERVER
|
||
if( m_hActor->GetWeapon( 1 ) && m_aeNeedEquipType[ 0 ] == m_hActor->GetWeapon( 1 )->GetEquipType()
|
||
&& m_hActor->GetWeapon( 0 ) && m_aeNeedEquipType[ 1 ] == m_hActor->GetWeapon( 0 )->GetEquipType() )
|
||
#else // _GAMESERVER
|
||
if( m_hActor->GetWeapon( 1, false ) && m_aeNeedEquipType[ 0 ] == m_hActor->GetWeapon( 1, false )->GetEquipType()
|
||
&& m_hActor->GetWeapon( 0, false ) && m_aeNeedEquipType[ 1 ] == m_hActor->GetWeapon( 0, false )->GetEquipType() )
|
||
#endif // _GAMESERVER
|
||
bSatisfy = true;
|
||
}
|
||
else
|
||
{
|
||
#ifdef _GAMESERVER
|
||
if( m_hActor->GetWeapon( 0 ) && m_aeNeedEquipType[ 0 ] == m_hActor->GetWeapon( 0 )->GetEquipType()
|
||
&& m_hActor->GetWeapon( 1 ) && m_aeNeedEquipType[ 1 ] == m_hActor->GetWeapon( 1 )->GetEquipType() )
|
||
#else // _GAMESERVER
|
||
if( m_hActor->GetWeapon( 0, false ) && m_aeNeedEquipType[ 0 ] == m_hActor->GetWeapon( 0, false )->GetEquipType()
|
||
&& m_hActor->GetWeapon( 1, false ) && m_aeNeedEquipType[ 1 ] == m_hActor->GetWeapon( 1, false )->GetEquipType() )
|
||
#endif // _GAMESERVER
|
||
bSatisfy = true;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for( int i=0; i<MAX_SKILL_NEED_EQUIP_COUNT; ++i )
|
||
{
|
||
if( CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ i ] )
|
||
{
|
||
for( int k=0; k<2; ++k )
|
||
{
|
||
// bActionMatchWeapon 를 디폴트로 true 로 호출하니까 액션에 따라 무기가 다르게 나오는 듯 하여 항상 차고 있는 메인 무기 위주로 체크토록..
|
||
#ifdef _GAMESERVER
|
||
if( m_hActor->GetWeapon( k ) && m_aeNeedEquipType[ i ] == m_hActor->GetWeapon( k )->GetEquipType() )
|
||
#else // _GAMESERVER
|
||
if( m_hActor->GetWeapon( k, false ) && m_aeNeedEquipType[ i ] == m_hActor->GetWeapon( k, false )->GetEquipType() )
|
||
#endif // _GAMESERVER
|
||
{
|
||
bSatisfy = true;
|
||
break;
|
||
}
|
||
}
|
||
if( bSatisfy )
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return bSatisfy;
|
||
}
|
||
|
||
CDnSkill::UsingResult CDnSkill::CanExecute( void )
|
||
{
|
||
UsingResult eResult = UsingResult::Failed;
|
||
|
||
if( !m_hActor )
|
||
return UsingResult::Failed;
|
||
|
||
if( m_hActor->IsPlayerActor() )
|
||
{
|
||
CDnPlayerActor* pPlayerActor = static_cast<CDnPlayerActor*>(m_hActor.GetPointer());
|
||
if( pPlayerActor && pPlayerActor->IsSwapSingleSkin() )
|
||
{
|
||
if( pPlayerActor->IsTransformSkill(GetClassID()) == false )
|
||
return UsingResult::Failed;
|
||
}
|
||
}
|
||
if (m_hActor->IsAppliedThisStateBlow(STATE_BLOW::BLOW_176))
|
||
{
|
||
DNVector(DnBlowHandle) vlBlows;
|
||
CDnAllowedSkillsBlow* pAllowedSkillBlow = NULL;
|
||
m_hActor->GatherAppliedStateBlowByBlowIndex(STATE_BLOW::BLOW_176, vlBlows);
|
||
for (int i = 0; i < (int)vlBlows.size(); ++i)
|
||
{
|
||
pAllowedSkillBlow = static_cast<CDnAllowedSkillsBlow*>(vlBlows[i].GetPointer());
|
||
if (!pAllowedSkillBlow) continue;
|
||
|
||
if (!pAllowedSkillBlow->IsAllowSkill(m_iSkillID))
|
||
return UsingResult::Failed;
|
||
}
|
||
}
|
||
|
||
// 잔여 SP 체크, 체력 체크, 레벨 체크 등등
|
||
// 오라나 토글은 현재 활성화 중이라면 MP 상관 없이 끌 수 있다.
|
||
if( !IsToggleOn() && !IsAuraOn() )
|
||
if( m_hActor->GetSP() < m_iNeedMP[ m_iSelectedSkillLevelDataApplyType ] )
|
||
return UsingResult::Failed;
|
||
|
||
// 워리어의 릴리브같은 스킬은 수면, 스턴 중일때도 사용가능해야 한다.
|
||
// 테이블에 공격불가 무시 발현타입을 추가할까하다가 현재 릴리브에서만 의미있는 것이므로
|
||
// 다른 곳에서 어떤 식으로 쓰이게 될지 좀 더 지켜보고 규격화 시키도록 한다.
|
||
// 우선 Dissolve 상태효과 있는 스킬은 행동 불가 체크를 건너뛴다.
|
||
// 스킬에 해당하는 액션의 State 시그널에 반드시 IgnorectCantAction 이 켜져 있어야 스킬 액션이 나간다.
|
||
bool bPassCheckCantAction = false;
|
||
for( DWORD i = 0; i < GetStateEffectCount(); ++i )
|
||
{
|
||
//#40480 결빙상태에서 단축슬롯 활성화를 위해서..
|
||
CDnSkill::StateEffectStruct* pSE = GetStateEffectFromIndex( i );
|
||
|
||
if( STATE_BLOW::BLOW_069 == pSE->nID )
|
||
{
|
||
// 76643 ( Dissolvable 이 2면 그냥 비활성화 해달라고 합니다 )
|
||
for( int i=0 ; i<m_hActor->GetNumAppliedStateBlow() ; ++i )
|
||
{
|
||
DnBlowHandle hBlow = m_hActor->GetAppliedStateBlow( i );
|
||
if( hBlow )
|
||
{
|
||
const CDnSkill::SkillInfo* pSkillInfo = hBlow->GetParentSkillInfo();
|
||
if( pSkillInfo && pSkillInfo->iDissolvable == 2 )
|
||
return UsingResult::Failed;
|
||
}
|
||
}
|
||
|
||
bPassCheckCantAction = true;
|
||
break;
|
||
}
|
||
|
||
if( STATE_BLOW::BLOW_155 == pSE->nID )
|
||
{
|
||
bPassCheckCantAction = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 스킬 사용불가 상태효과가 있으면 mp 소모하는 스킬은 사용할 수 없다.
|
||
if( 0 < m_hActor->GetCantUseSkillSEReferenceCount() )
|
||
if( 0 < m_iNeedMP[ m_iSelectedSkillLevelDataApplyType ] )
|
||
return UsingResult::Failed;
|
||
|
||
// 67번 스킬 제한 상태효과가 있으면 액티브 스킬은 사용할 수 없음.
|
||
if( m_eSkillType == CDnSkill::Active )
|
||
{
|
||
int iAppliedStateBlow = m_hActor->GetNumAppliedStateBlow();
|
||
for( int iBlow = 0; iBlow < iAppliedStateBlow; ++iBlow )
|
||
{
|
||
DnBlowHandle hBlow = m_hActor->GetAppliedStateBlow( iBlow );
|
||
if( hBlow && hBlow->GetBlowIndex() == STATE_BLOW::BLOW_067 )
|
||
return UsingResult::Failed;
|
||
}
|
||
}
|
||
|
||
// HP
|
||
if( m_hActor->GetHP() < m_iNeedHP[ m_iSelectedSkillLevelDataApplyType ] )
|
||
return UsingResult::Failed;
|
||
|
||
bool isCharacterLevelCheck = true;
|
||
//스킬 레벨업 아이템에 의해 스킬레벨업이 된 스킬은 캐릭터 레벨 체크 하지 않도록 한다.
|
||
isCharacterLevelCheck = (GetLevelUpValue() == 0);
|
||
|
||
if (isCharacterLevelCheck)
|
||
{
|
||
if( m_hActor->GetLevel() < m_iLevelLimit )
|
||
return UsingResult::Failed;
|
||
}
|
||
|
||
// 필요 무기가 있다면 장착했는지 확인. 최대 2개임. 둘 중 하나만 충족되도 스킬 사용 가능.
|
||
if( (CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ 0 ]) ||
|
||
(CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ 1 ]) )
|
||
{
|
||
bool bSatisfy = false;
|
||
for( int i = 0; i < MAX_SKILL_NEED_EQUIP_COUNT; ++i )
|
||
{
|
||
if( CDnWeapon::EquipTypeEnum_Amount != m_aeNeedEquipType[ i ] )
|
||
{
|
||
for( int k = 0; k < 2; ++k )
|
||
{
|
||
// #11120 관련. 발차기 상태에서는 장착하고 있는 무기를 얻지 못하기 때문에 명시적으로 원래 함수로 장착하고 있는 무기를 얻어오자.
|
||
if( m_hActor->CDnActor::GetWeapon( k ) && m_aeNeedEquipType[ i ] == m_hActor->CDnActor::GetWeapon( k )->GetEquipType() )
|
||
{
|
||
bSatisfy = true;
|
||
break;
|
||
}
|
||
}
|
||
if( bSatisfy )
|
||
break;
|
||
}
|
||
}
|
||
|
||
if( false == bSatisfy )
|
||
return UsingResult::Failed;
|
||
}
|
||
|
||
// 화살 같은 소모성 아이템의 갯수 확인
|
||
bool bCheckNeedItem = true;
|
||
if( GetRoom() && bIsExtremitySkill() && static_cast<CDNGameRoom*>(GetRoom())->bIsLadderRoom() ) // 래더에서 궁극기 스킬
|
||
bCheckNeedItem = false;
|
||
|
||
if( bCheckNeedItem && m_iNeedItemID[ m_iSelectedSkillLevelDataApplyType ] > 0 )
|
||
{
|
||
int iNumNeedItem = CDnItemTask::GetInstance( m_hActor->GetRoom() ).ScanItemFromID( m_hActor, m_iNeedItemID[ m_iSelectedSkillLevelDataApplyType ], NULL );
|
||
if( iNumNeedItem < m_iNeedItemDecreaseCount[ m_iSelectedSkillLevelDataApplyType ] )
|
||
return UsingResult::Failed;
|
||
}
|
||
// 직업 체크
|
||
//if( m_hActor->GetClassID() <= CDnActor::Reserved6 )
|
||
if( m_hActor->IsPlayerActor() )
|
||
{
|
||
//CDnPlayerActor* pActor = dynamic_cast<CDnPlayerActor*>(m_hActor.GetPointer());
|
||
CDnPlayerActor* pActor = static_cast<CDnPlayerActor*>(m_hActor.GetPointer());
|
||
if( NULL == pActor )
|
||
return UsingResult::Failed;
|
||
if( 0 != m_iNeedJobClassID )
|
||
{
|
||
if( pActor->IsPassJob( m_iNeedJobClassID ) == false )
|
||
return UsingResult::Failed;
|
||
}
|
||
|
||
// 배틀 모드가 아니면 스킬 발동 불가!
|
||
if( !pActor->IsBattleMode() )
|
||
return UsingResult::Failed;
|
||
}
|
||
|
||
switch( m_eDurationType )
|
||
{
|
||
case CDnSkill::Instantly:
|
||
case CDnSkill::Buff:
|
||
case CDnSkill::Debuff:
|
||
case CDnSkill::SummonOnOff:
|
||
case CDnSkill::StanceChange:
|
||
{
|
||
// 쿨타임이 끝나지 않았다면 스킬 발동 불가.. 우선 클라에서 체크해서 보내주므로 서버에선 약간의 유예 시간을 남겨둔다.
|
||
// 몬스터이거나 오토 패시브 스킬인 경우엔 칼같이 체크.
|
||
if( m_hActor->IsMonsterActor() ||
|
||
SkillTypeEnum::AutoPassive == m_eSkillType )
|
||
{
|
||
if( m_fCoolTime > 0.0f )
|
||
return UsingResult::FailedByCooltime;
|
||
}
|
||
else
|
||
{
|
||
if( m_fLeftDelayTime > 0.5f )
|
||
return UsingResult::FailedByCooltime;
|
||
}
|
||
}
|
||
break;
|
||
|
||
case CDnSkill::TimeToggle:
|
||
break;
|
||
|
||
case CDnSkill::ActiveToggle:
|
||
case CDnSkill::ActiveToggleForSummon:
|
||
break;
|
||
|
||
case CDnSkill::Aura:
|
||
break;
|
||
}
|
||
|
||
if( m_vlpUsableCheckers[ m_iSelectedSkillLevelDataApplyType ].empty() )
|
||
eResult = UsingResult::Success;
|
||
else
|
||
{
|
||
int iNumChecker = (int)m_vlpUsableCheckers[ m_iSelectedSkillLevelDataApplyType ].size();
|
||
|
||
for( int iChecker = 0; iChecker < iNumChecker; ++iChecker )
|
||
{
|
||
IDnSkillUsableChecker* pChecker = m_vlpUsableCheckers[ m_iSelectedSkillLevelDataApplyType ].at( iChecker );
|
||
if( false == pChecker->CanUse() )
|
||
{
|
||
eResult = UsingResult::FailedByUsableChecker;
|
||
break;
|
||
}
|
||
else
|
||
eResult = UsingResult::Success;
|
||
}
|
||
}
|
||
|
||
return eResult;
|
||
}
|
||
|
||
|
||
|
||
float CDnSkill::GetDelayTime( void )
|
||
{
|
||
|
||
#if defined(PRE_ADD_TOTAL_LEVEL_SKILL)
|
||
float fDelayTime = 0.0f;
|
||
|
||
if( 0.0f < m_fAnotherGlobalSkillCoolTime )
|
||
{
|
||
fDelayTime = m_fAnotherGlobalSkillCoolTime;
|
||
|
||
DnSkillHandle hAnotherSkill;
|
||
if (m_hActor)
|
||
hAnotherSkill = m_hActor->FindSkill(m_nAnotherGlobakSkillID);
|
||
|
||
if (hAnotherSkill)
|
||
{
|
||
if (hAnotherSkill->GetAnotherGlobalSkillID() != GetClassID())
|
||
fDelayTime = hAnotherSkill->GetDelayTime();
|
||
}
|
||
}
|
||
else
|
||
//위m_fAnotherGlobalSkillCoolTime이 적용 되어 있으면 적용 안 하도록..
|
||
{
|
||
fDelayTime = m_fDelayTime[ m_iSelectedSkillLevelDataApplyType ];
|
||
|
||
float fGlobalCoolTimeRate = 0.0f;
|
||
if (m_hActor &&
|
||
m_hActor->IsAppliedThisStateBlow(STATE_BLOW::BLOW_269) &&
|
||
m_iGlobalSkillGroupID > 0)
|
||
{
|
||
DNVector(DnBlowHandle) vlBlows;
|
||
m_hActor->GatherAppliedStateBlowByBlowIndex(STATE_BLOW::BLOW_269, vlBlows);
|
||
{
|
||
int nCount = (int)vlBlows.size();
|
||
for (int i = 0; i < nCount; ++i)
|
||
{
|
||
DnBlowHandle hBlow = vlBlows[i];
|
||
if (hBlow && hBlow->IsEnd() == false)
|
||
{
|
||
fGlobalCoolTimeRate += hBlow->GetFloatValue();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
fDelayTime -= fDelayTime * fGlobalCoolTimeRate;
|
||
}
|
||
|
||
return fDelayTime;
|
||
#else
|
||
if( 0.0f < m_fAnotherGlobalSkillCoolTime )
|
||
return m_fAnotherGlobalSkillCoolTime;
|
||
|
||
return m_fDelayTime[ m_iSelectedSkillLevelDataApplyType ];
|
||
#endif // PRE_ADD_TOTAL_LEVEL_SKILL
|
||
}
|
||
|
||
|
||
void CDnSkill::OnBeginCoolTime()
|
||
{
|
||
m_dwLastUseSkillTimeStamp = timeGetTime();
|
||
|
||
m_fCoolTime = (GetDelayTime() == 0.0f) ? 0.0f : 1.0f;
|
||
|
||
m_fCoolTimeAdjustBlowValue = 1.0f;
|
||
|
||
m_fLeftDelayTime = GetDelayTime()*m_fCoolTimeAdjustBlowValue;
|
||
|
||
m_fLeftDelayTime *= m_fCoolTimeMultipier;
|
||
|
||
// [2011/03/09 semozz]
|
||
// 시작할때 LeftDelayTime이 0.0이 되면 m_fCoolTime을 0.0f로 변경해야한다.
|
||
// 그렇지 않으면 쿨타임이 1.0으로 계속 유지됨.(Process함수에서 m_fLeftDelayTime이 0이면 CoolTime갱신안됨.
|
||
if (m_fLeftDelayTime == 0.0f)
|
||
{
|
||
m_fCoolTime = 0.0f;
|
||
|
||
#if defined(PRE_ADD_TOTAL_LEVEL_SKILL)
|
||
m_fDeltaGlobalCoolTime = 0.0f;
|
||
#endif // PRE_ADD_TOTAL_LEVEL_SKILL
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void CDnSkill::_OnBeginProcessException( void )
|
||
{
|
||
// 결빙상태에서 워리어 릴리브 스킬을 쓰는 경우 바로 프레임 고정을 풀어준다. #12438
|
||
// 결빙상태효과가 걸린 상태에서 디버프 상태효과 해제 상태효과가 self 로 적용되는 스킬을
|
||
// 사용하는 경우로 일반화 시킴.
|
||
if( m_hActor &&
|
||
(
|
||
m_hActor->IsAppliedThisStateBlow( STATE_BLOW::BLOW_041 ) ||
|
||
m_hActor->IsAppliedThisStateBlow( STATE_BLOW::BLOW_146 ) ||
|
||
m_hActor->IsAppliedThisStateBlow( STATE_BLOW::BLOW_218 ) //#53900 Escape스킬 추가
|
||
))
|
||
{
|
||
int iNumStateBlow = (int)m_vlStateEffectList[ m_iSelectedSkillLevelDataApplyType ].size();
|
||
for( int i = 0; i < iNumStateBlow; ++i )
|
||
{
|
||
const StateEffectStruct& SE = m_vlStateEffectList[ m_iSelectedSkillLevelDataApplyType ].at( i );
|
||
if( STATE_BLOW::BLOW_069 == SE.nID &&
|
||
StateEffectApplyType::ApplySelf == SE.ApplyType )
|
||
{
|
||
// 프레임 정지 상태효과 참조 인덱스를 모두 풀어준다. 프레임이 돌아야 액션이 돌아가고
|
||
// 액션이 돌아가야 릴리브 상태효과가 들어간다.
|
||
while( 0 < m_hActor->GetFrameStopRefCount() )
|
||
m_hActor->RemovedFrameStop();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//낙인 상태효과 제거
|
||
ClearStigmaStateEffect();
|
||
}
|
||
|
||
void CDnSkill::ClearStigmaStateEffect()
|
||
{
|
||
//////////////////////////////////////////////////////////////////////////
|
||
//낙인 상태효과가 있는 스킬인지 확인...
|
||
bool hasStigmaState = false;
|
||
int nListCount = (int)m_vlStateEffectList[m_iSelectedSkillLevelDataApplyType].size();
|
||
for (int i = 0; i < nListCount; ++i)
|
||
{
|
||
const StateEffectStruct& SE = m_vlStateEffectList[ m_iSelectedSkillLevelDataApplyType ].at( i );
|
||
if (SE.nID == STATE_BLOW::BLOW_246)
|
||
{
|
||
hasStigmaState = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//주위 낙인 효과를 찾아서 제거 해준다...
|
||
if (hasStigmaState == true)
|
||
{
|
||
DNVector(DnActorHandle) hVecList;
|
||
m_hActor->ScanActor(m_hActor->GetRoom(), *m_hActor->GetPosition(), FLT_MAX, hVecList);
|
||
|
||
int nActorCount = (int)hVecList.size();
|
||
for (int i = 0; i < nActorCount; ++i)
|
||
{
|
||
DnActorHandle hActor = hVecList[i];
|
||
if (hActor && hActor->IsDie() == false && hActor->IsAppliedThisStateBlow(STATE_BLOW::BLOW_246))
|
||
{
|
||
DNVector(DnBlowHandle) vlhBlows;
|
||
hActor->GetStateBlow()->GetStateBlowFromBlowIndex( STATE_BLOW::BLOW_246, vlhBlows );
|
||
int iNumBlow = (int)vlhBlows.size();
|
||
for( int j = 0; j < iNumBlow; ++j )
|
||
{
|
||
DnBlowHandle hBlow = vlhBlows[j];
|
||
if (hBlow && hBlow->IsEnd() == false)
|
||
{
|
||
CDnSkill::SkillInfo* pSkillInfo = const_cast<CDnSkill::SkillInfo*>(hBlow->GetParentSkillInfo());
|
||
if (pSkillInfo && pSkillInfo->hSkillUser == m_hActor)
|
||
{
|
||
int nBlowID = hBlow->GetBlowID();
|
||
hActor->SendRemoveStateEffectFromID(nBlowID); //제거 패킷 보내고
|
||
hActor->GetStateBlow()->RemoveImediatlyStateEffectFromID(nBlowID); //즉시 제거 한다.
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
//////////////////////////////////////////////////////////////////////////
|
||
}
|
||
|
||
// 스킬에 달려있는 Processor 들 중에 선처리 해야하는 것들 먼저 처리.
|
||
void CDnSkill::CheckProcessorOnBegin( void )
|
||
{
|
||
CheckChangeActionStrByBubbleProcessor();
|
||
CheckStateEffectApplyOnOffByBubbleProcessor();
|
||
}
|
||
|
||
void CDnSkill::CheckChangeActionStrByBubbleProcessor( void )
|
||
{
|
||
CDnChangeActionStrByBubbleProcessor* pProcessor = static_cast<CDnChangeActionStrByBubbleProcessor*>(GetProcessor( IDnSkillProcessor::CHANGE_ACTIONSTR_BY_BUBBLE ));
|
||
if( pProcessor )
|
||
{
|
||
bool bChanged = false;
|
||
const char* pChangedActionName = pProcessor->GetChangeActionNameAndRemoveNeedBubble( &bChanged );
|
||
if( bChanged )
|
||
{
|
||
// 액션을 바꿔준다.
|
||
CDnPlayAniProcess* pPlayAniProcessor = static_cast<CDnPlayAniProcess*>(GetProcessor( IDnSkillProcessor::PLAY_ANI ));
|
||
if (pPlayAniProcessor)
|
||
pPlayAniProcessor->ChangeActionNameOnce( pChangedActionName );
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void CDnSkill::CheckStateEffectApplyOnOffByBubbleProcessor( void )
|
||
{
|
||
// 버블 갯수에 따라 상태효과 갯수를 변경시키는 Processor
|
||
CDnStateEffectApplyOnOffByBubbleProcessor* pProcessor = static_cast<CDnStateEffectApplyOnOffByBubbleProcessor*>(GetProcessor(IDnSkillProcessor::STATE_EFFECT_APPLY_ONOFF_BY_BUBBLE));
|
||
if( pProcessor )
|
||
{
|
||
pProcessor->SelectAvailableSE( m_vlStateEffectList[ m_iSelectedSkillLevelDataApplyType ] );
|
||
}
|
||
}
|
||
|
||
|
||
void CDnSkill::OnBegin( LOCAL_TIME LocalTime, float fDelta )
|
||
{
|
||
ApplyAddtionalStateInfo();
|
||
|
||
// 등록된 옵저버에게 스킬 사용 메시지 보냄.
|
||
boost::shared_ptr<IDnObserverNotifyEvent> pNotifyEvent( new CDnUseSkillMessage );
|
||
boost::shared_ptr<CDnUseSkillMessage> pSkillUseEvent = shared_polymorphic_downcast<CDnUseSkillMessage>( pNotifyEvent );
|
||
pSkillUseEvent->SetSkillID( m_iSkillID );
|
||
CDnObservable::Notify( pNotifyEvent );
|
||
|
||
CheckProcessorOnBegin();
|
||
|
||
// 같은 글로벌 ID 를 사용하는 다른 글로벌 스킬을 사용하여 셋팅된 쿨타임 값을 실제로 이 스킬 사용될 때는 제거한다.
|
||
m_fAnotherGlobalSkillCoolTime = 0.0f;
|
||
|
||
m_nAnotherGlobakSkillID = 0;
|
||
|
||
m_SkillStartTime = LocalTime;
|
||
//m_LastAuraCheckTime = 0;
|
||
|
||
#if defined( PRE_ADD_ACADEMIC ) // 소환형 몬스터 액티브 토글 스킬은 쿨타임이 돌필요가 없습니다.
|
||
if(m_eDurationType != DurationTypeEnum::ActiveToggleForSummon)
|
||
//OnBeginCoolTime();
|
||
|
||
{
|
||
//--------------------------------------------------
|
||
//[debug_skill] server
|
||
//세콘늴鑒 |