#include "stdafx.h" #include "SGameWork.h" #include "SGameMessage.h" #include "GameDefine.h" #include "SGame.h" #include "SMotionDB.h" #include "SStringDB.h" #include "SMonsterDB.h" #include "SCreatureDB.h" #include "SNpcDB.h" #include "SGameUtil.h" #include "SItemDB.h" #include "SGameAvatarEx.h" #include "SSkillStageType.h" #include "SGameOtherEffectMng.h" #include "LuaVM.h" #include #include "SSoundResourceDB.h" #include "SDebug_Util.h" #include "SGameWorld.h" #include "SGameSystem.h" #include "CommonUtil.h" #include "SGameScript.h" // Fraun performance tweak extern SGameSystem * g_pCurrentGameSystem; namespace { const char* szNX3Name[3][2] = { { "gam.nx3", "gaf.nx3", }, { "dem.nx3", "def.nx3", }, { "asm.nx3", "asf.nx3", }, }; const char* GetNX3Name( int nRace, int nSex ) { short race = 0; if( nRace == GCLAN_GAIA ) race = 0; else if( nRace == GCLAN_DEVA ) race = 1; else if( nRace == GCLAN_ASURA ) race = 2; else { assert( false && "유효하지 않는 종족" ); return ""; } short sex = 0; if( nSex == SEX_MALE ) sex = 0; else if( nSex == SEX_FEMALE ) sex = 1; else { assert( false && "유효하지 않는 성별" ); return ""; } return szNX3Name[race][sex]; } }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SGameWork::SGameWork( SGameAvatarEx *pOwner, int nCount, DWORD dwKeepTime ) : m_nCount(nCount), m_dwStartTime(0), m_dwKeepTime(dwKeepTime), m_dwTime(0), m_pOwner(pOwner), m_bEnd(FALSE), m_nStep(STEP_00), m_nWorkType( WORK_NONE ) { } SGameWork::~SGameWork() { } void SGameWork::Process( DWORD dwTime ) { } void SGameWork::_setEvent( KEventKeyRes* srcEvent, KEventKeyRes* & dstEvent ) { dstEvent = NULL; if( srcEvent ) { dstEvent = new KEventKeyRes; dstEvent->SetKeyCount( srcEvent->GetKeyCount(), srcEvent->GetLength() ); for( int i(0); srcEvent->GetKeyCount()>i; i++ ) dstEvent->SetKey( i, &srcEvent->GetKey(i) ); } } void SGameWork::SetDamageDisplayName( SMSG_DAMAGE* pDamage, SGameAvatarEx* pTarget ) { // Fraun performance tweak if( m_pOwner ) { switch (m_pOwner->GetObjType()) { case TS_ENTER::GAME_PLAYER: { pDamage->strCasterName = m_pOwner->GetName(); break; } case TS_ENTER::GAME_MOB: { pDamage->strCasterName = GetStringDB().GetString(GetMonsterDB().GetTextID(m_pOwner->GetContentID())); break; } case TS_ENTER::GAME_SUMMON: { pDamage->strCasterName = GetStringDB().GetString(GetCreatureDB().GetTextID(m_pOwner->GetContentID())); break; } case TS_ENTER::GAME_NPC: { pDamage->strCasterName = GetStringDB().GetString(GetNpcDB().GetTextID(m_pOwner->GetContentID())); break; } } } if( pTarget ) { switch (m_pOwner->GetObjType()) { case TS_ENTER::GAME_PLAYER: { pDamage->strTargetName = pTarget->GetName(); break; } case TS_ENTER::GAME_MOB: { pDamage->strTargetName = GetStringDB().GetString(GetMonsterDB().GetTextID(pTarget->GetContentID())); break; } case TS_ENTER::GAME_SUMMON: { pDamage->strTargetName = GetStringDB().GetString(GetCreatureDB().GetTextID(pTarget->GetContentID())); break; } case TS_ENTER::GAME_NPC: { pDamage->strTargetName = GetStringDB().GetString(GetNpcDB().GetTextID(pTarget->GetContentID())); break; } } } } void SGameWork::SetWorkType( WORK_TYPE nWorkType ) { m_nWorkType = nWorkType; } // 2010.06.14 - prodongi void SGameWork::SetStep(int nStep) { m_nStep = nStep; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //캐릭터 이모션 관련 SWorkEmotion::SWorkEmotion( class SGameAvatarEx * pOwner, struct SGameMessage * pMsg ) : SGameWork( pOwner ) { if( pMsg ) { //TODO : 서버에서 처리 해주면 추가 가능. } m_nEmotionID = -1; SetStep(STEP_01); } SWorkEmotion::~SWorkEmotion() { if( m_pOwner ) m_pOwner->HideWeapon( TRUE ); } bool SWorkEmotion::SetEmotion( int nEmotionID ) { if( m_pOwner->GetCurrAnimationID() == nEmotionID ) { SetEnd( true ); return false; } m_nEmotionID = nEmotionID; return true; } void SWorkEmotion::Process( DWORD dwTime ) { if( IsEnd() ) return; if( m_pOwner->GetInnObjType() != m_pOwner->GetObjType() ) { SetEnd( true ); return; } if( m_nEmotionID == -1 ) { //초기화 안 됐음 SetEnd(TRUE); return; } if( GetStep() == STEP_01 ) { //Emotion이 가능 한가 검사 if( m_pOwner->IsAniLock() || m_pOwner->GetAttackAniLock() ) { SetEnd(TRUE); return; } if( !m_pOwner->CheckAllState() ) { SetEnd(TRUE); return; } if( m_nEmotionID == ANI_PRAY && IsRamadanPrayRoom() == false ) // 기도실이 아니면 기도는 할 수 없다 { SetEnd(TRUE); return ; } //FALSE가 무기 숨김 //TRUE가 무기 보여줌 if( ANI_CHEER != m_nEmotionID ) m_pOwner->HideWeapon( FALSE ); SetStep(STEP_02); } else if( GetStep() == STEP_02 ) { m_pOwner->NPlayAnimation( m_nEmotionID ); SetStep(STEP_03); } else if( GetStep() == STEP_03 ) { if( !m_pOwner->IsPlaying() && m_pOwner->GetCurrAnimationID() == m_nEmotionID ) { m_pOwner->HideWeapon( TRUE ); m_pOwner->Default(); SetEnd(TRUE); } if( m_pOwner->GetCurrAnimationID() != m_nEmotionID ) { m_pOwner->HideWeapon( TRUE ); SetEnd(TRUE); } } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SWorkAttackEx SWorkAttackEx::SWorkAttackEx( class SGameAvatarEx * pOwner, const AR_HANDLE target, float fAttackPlayRate ) : SGameWork( pOwner ) { m_Target = target; //타겟 m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_Target ); if( !m_pTarget ) { SetEnd(TRUE); return; } // _oprint( "SWorkAttackEx : fRate[%f]\n", m_fAttackRate ); ZeroMemory( m_pDamageSet, sizeof( m_pDamageSet ) ); m_nHitCount = 0; m_nSwingCnt = 0; m_nMaxHitCount = 0; m_fAttackPlayRate = fAttackPlayRate; pOwner->SetVisibleWeaponTrail( true ); SetWorkType( WORK_ATTACKEX ); } SWorkAttackEx::~SWorkAttackEx() { if( !m_vFX_List.empty() ) { if( m_pOwner ) { for( unsigned int i(0); m_vFX_List.size()>i; i++ ) m_pOwner->DelEffect(m_vFX_List[i]); } m_vFX_List.erase( m_vFX_List.begin(), m_vFX_List.end() ); } if( m_pOwner ) m_pOwner->SetAttackAniLock( false ); if( m_pOwner ) { //처리가 안된 데미지 처리한다 while( m_nHitCount > 0 ) { SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_Target ); if( pTarget ) { SMSG_DAMAGE *pDamage = m_pDamageSet[m_nMaxHitCount-m_nHitCount]; _processDamage( pDamage, m_nHitCount, SMotionEventHanderDB::EV_HIT, -1 ); } else { break; } } } for( short i = 0; i < 4; i++ ) { SAFE_DELETE( m_pDamageSet[i] ); } SAFE_DELETE( m_pEventHandle06 ); SAFE_DELETE( m_pEventHandle05 ); SAFE_DELETE( m_pEventHandle04 ); SAFE_DELETE( m_pEventHandle03 ); SAFE_DELETE( m_pEventHandle02 ); SAFE_DELETE( m_pEventHandle01 ); SAFE_DELETE( m_pEventHandle00_sound ); SAFE_DELETE( m_pEventHandle00_effect ); SAFE_DELETE( m_pEventHandle00_motion_effect ); } void SWorkAttackEx::SetEventHandle( const DWORD dwStartTime, const unsigned short attack_speed, KEventKeyRes* pEvent00_eff, KEventKeyRes* pEvent00_sound, KEventKeyRes* pEvent00_motion_effect, KEventKeyRes* pEvent01, KEventKeyRes* pEvent02, KEventKeyRes* pEvent03, KEventKeyRes* pEvent04, KEventKeyRes* pEvent05, KEventKeyRes* pEvent06 ) { m_dwStartTime = dwStartTime; //공격 시작 시간 m_dwMaxTime = attack_speed; //공격 전체 시간 _setEvent( pEvent00_eff , m_pEventHandle00_effect ); _setEvent( pEvent00_sound, m_pEventHandle00_sound ); _setEvent( pEvent00_motion_effect, m_pEventHandle00_motion_effect ); _setEvent( pEvent01, m_pEventHandle01 ); _setEvent( pEvent02, m_pEventHandle02 ); _setEvent( pEvent03, m_pEventHandle03 ); _setEvent( pEvent04, m_pEventHandle04 ); _setEvent( pEvent05, m_pEventHandle05 ); _setEvent( pEvent06, m_pEventHandle06 ); int nLength = 0; if( pEvent00_eff ) nLength = pEvent00_eff->GetLength(); else if( pEvent00_sound ) nLength = pEvent00_sound->GetLength(); else if( pEvent00_motion_effect ) nLength = pEvent00_motion_effect->GetLength(); else if( pEvent01 ) nLength = pEvent01->GetLength(); else if( pEvent02 ) nLength = pEvent02->GetLength(); else if( pEvent03 ) nLength = pEvent03->GetLength(); else if( pEvent04 ) nLength = pEvent04->GetLength(); else if( pEvent05 ) nLength = pEvent05->GetLength(); else if( pEvent06 ) nLength = pEvent06->GetLength(); float fAttack = m_pOwner->GetAttackSpeed( attack_speed ); float fRate = GetAniPlayRate( fAttack, nLength ); // _oprint( "SGameAttackEx : total[%d], fAttack[%f], fRate[%f]\n", attack_speed, fAttack, fRate ); m_fAttackRate = fRate; //진행 배속 //#ifndef NDEBUG // if( m_pOwner && m_pOwner->IsLocalPlayer() ) // _oprint( "Work Attack Speed : %d, %f\n", attack_speed, 4.8f / fRate ); //#endif //Half 시간 설정 if( m_pOwner->GetObjType() == TS_ENTER::GAME_MOB || m_pOwner->GetObjType() == TS_ENTER::GAME_SUMMON ) { //Mouvement de dégâts possible lorsque la progression est supérieure à 50 % m_dwHalfTime = (nLength/fRate)/2.f; } else if( m_pOwner->GetObjType() == TS_ENTER::GAME_PLAYER ) { //Le mouvement des dégâts est possible lorsque la progression est supérieure à 70 % m_dwHalfTime = (nLength / fRate) - ((nLength / fRate) * 0.3f); } //assert( m_dwHalfTime && "공격 시간이 이상함!!!" ); m_dwHalfTime += dwStartTime; //이번 공격이 끝날 시점 m_dwMaxTime += dwStartTime; //현재 시간을 더해서 끝날 시간을 생성 } void SWorkAttackEx::SetDamegeMsg( struct SMSG_ATTACK * pAttackMsg ) { for( short i(0); i < 4; i++ ) { SAFE_DELETE( m_pDamageSet[i] ); } SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_Target ); for( m_nMaxHitCount = 0; m_nMaxHitCount < pAttackMsg->count; m_nMaxHitCount++ ) { m_pDamageSet[m_nMaxHitCount] = new SMSG_DAMAGE; m_pDamageSet[m_nMaxHitCount]->attacker_handle = pAttackMsg->attacker_handle; m_pDamageSet[m_nMaxHitCount]->target_handle = pAttackMsg->target_handle; m_pDamageSet[m_nMaxHitCount]->attack_action = pAttackMsg->attack_action; m_pDamageSet[m_nMaxHitCount]->attack_flag = pAttackMsg->attack_flag; m_pDamageSet[m_nMaxHitCount]->flag = pAttackMsg->m_vAttackInfoList[m_nMaxHitCount].flag; m_pDamageSet[m_nMaxHitCount]->nDamage = pAttackMsg->m_vAttackInfoList[m_nMaxHitCount].damage; SetDamageDisplayName( m_pDamageSet[m_nMaxHitCount], pTarget ); for( int count(0); CreatureElemental::ElementalType::COUNT>count; count++ ) m_pDamageSet[m_nMaxHitCount]->elemental_damage[count] = pAttackMsg->m_vAttackInfoList[m_nMaxHitCount].elemental_damage[count]; } m_nSwingCnt = m_nHitCount = m_nMaxHitCount; } void SWorkAttackEx::SetDamegeInfo( const struct SStateInfo * pStateInfo ) { for( short i(0); i < 4; i++ ) { SAFE_DELETE( m_pDamageSet[i] ); } SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_Target ); for( m_nMaxHitCount = 0; m_nMaxHitCount < pStateInfo->count; m_nMaxHitCount++ ) { m_pDamageSet[m_nMaxHitCount] = new SMSG_DAMAGE; m_pDamageSet[m_nMaxHitCount]->attacker_handle = pStateInfo->hSelf; m_pDamageSet[m_nMaxHitCount]->target_handle = pStateInfo->hTarget; m_pDamageSet[m_nMaxHitCount]->attack_action = pStateInfo->attack_action; m_pDamageSet[m_nMaxHitCount]->attack_flag = pStateInfo->attack_flag; m_pDamageSet[m_nMaxHitCount]->flag = pStateInfo->vAttackInfoList[m_nMaxHitCount].flag; m_pDamageSet[m_nMaxHitCount]->nDamage = pStateInfo->vAttackInfoList[m_nMaxHitCount].damage; SetDamageDisplayName( m_pDamageSet[m_nMaxHitCount], pTarget ); for( int count(0); CreatureElemental::ElementalType::COUNT>count; count++ ) m_pDamageSet[m_nMaxHitCount]->elemental_damage[count] = pStateInfo->vAttackInfoList[m_nMaxHitCount].elemental_damage[count]; } m_nSwingCnt = m_nHitCount = m_nMaxHitCount; } bool SWorkAttackEx::ProcessingDamage() { if( m_nHitCount > 0 ) return false; return true; } void SWorkAttackEx::_ondamage( struct SMSG_DAMAGE * pDamage, int & nHitCnt, int nKeyHandleID, int nKeyTime ) { // Fraun performance tweak if( pDamage && nHitCnt > 0) { AR_HANDLE ownerHandle = m_pOwner->GetArID(); AR_HANDLE targetHandle = m_pTarget->GetArID(); m_pOwner->OnDamage(ownerHandle, targetHandle, pDamage); if (!(pDamage->flag & TS_ATTACK_EVENT::FLAG_MISS)) { int nMaterial = 0; int nWeaponClass = 0; bool bCrit = pDamage->flag & TS_ATTACK_EVENT::FLAG_CRITICAL; bool bBlock = pDamage->flag & TS_ATTACK_EVENT::FLAG_BLOCK; SGame* pGame = g_pCurrentGameSystem->GetGame(); if (pGame) { SGameObject* pPlayer = pGame->GetGameObject(targetHandle); if (pPlayer) { nMaterial = pPlayer->GetMaterial(); nWeaponClass = pPlayer->GetItemClass(); } } Noscript_PlayFX(ownerHandle, ownerHandle, targetHandle, nMaterial, nWeaponClass, bCrit, bBlock, nKeyHandleID, nKeyTime); //void Noscript_PlayFX(AR_HANDLE owner_handle, AR_HANDLE attack_handle, AR_HANDLE target_handle, int nMaterial, int nWeaponClass, bool bIsCritical, bool bIsBlock, int nKeyHandleID, int nKeyTime) m_pTarget->Damage(); } nHitCnt--; } } void SWorkAttackEx::_processDamage( struct SMSG_DAMAGE * pDamage, int & nHitCnt, int nKeyHandleID, int nKeyTime ) { m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_Target ); if( !m_pTarget ) { SetEnd(TRUE); return; } if( pDamage ) _ondamage( pDamage, nHitCnt, nKeyHandleID, nKeyTime ); } void SWorkAttackEx::_processEvent( KEventKeyRes* event, DWORD eventTime ) { if( event ) { Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; event->GetData( eventTime, pKey1, pKey2 ); if( pKey1 && !pKey1->bUse ) { pKey1->bUse = true; //std::string strScript; //힛팅임. if( pKey1->nHandleID == SMotionEventHanderDB::EV_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_LEFT_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_RIGHT_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_TWO_HAND_HIT) { if( m_nHitCount ) _processDamage( m_pDamageSet[m_nMaxHitCount-m_nHitCount], m_nHitCount, pKey1->nHandleID, pKey1->time ); } else { if( m_nSwingCnt && (pKey1->nHandleID == SMotionEventHanderDB::EV_SHOOT || pKey1->nHandleID == SMotionEventHanderDB::EV_SWING) ) { m_nSwingCnt--; //XStringUtil::Format( strScript, "%s( %u, %u )", "call_fx_ch_weapone_attack", m_pOwner->GetArID(), m_pTarget->GetArID() ); } } // Fraun performance tweak (TODO: return it back; testing purposes!) //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); } } } void SWorkAttackEx::Process( DWORD dwTime ) { if( IsEnd() ) return; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_Target ); if( !m_pTarget ) { SetEnd(TRUE); return; } if( dwTime >= m_dwHalfTime ) { //공격 시간이 50% 지났다. m_pOwner->SetAttackAniLock( false ); } if( dwTime >= m_dwMaxTime ) { //시간이 모두 지났다. // _oprint( "SWorkAttackEx 종료 02\n" ); m_pOwner->SetAttackAniLock( false ); SetEnd(TRUE); return; } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fAttackRate); //_oprint( " 공격 : %d\n", eventTime ); if( m_pEventHandle00_effect ) { //시작 되자 마자 나오는 Effect Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; m_pEventHandle00_effect->GetData( 0, pKey1, pKey2 ); if( pKey1 && !pKey1->bUse ) { pKey1->bUse = true; m_pOwner->FindMotionAddOnFx( pKey1 ); switch(pKey1->nSpeedType) { case 0: { m_pOwner->AddEffect( &FX_DATA_EX( pKey1->strEffect.c_str(), pKey1->followflag, m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), pKey1->nEffPos, false, pKey1->nSpeedType, m_fAttackPlayRate ) ); } break; case 2: { if(!pKey1->strEffect.empty()) { m_pOwner->AddEffect( &FX_DATA_EX( pKey1->strEffect.c_str(), pKey1->followflag, m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), pKey1->nEffPos, false, pKey1->nSpeedType, m_fAttackPlayRate ) ); } //검 잔상 m_pOwner->ActivateFxSwordSlashForSkill(); } break; } } } if( m_pEventHandle00_sound ) { Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; m_pEventHandle00_sound->GetData( eventTime, pKey1, pKey2 ); if( pKey1 && !pKey1->bUse ) { pKey1->bUse = true; if( pKey1->nSound_play_probability != 100 ) { int nRatio = rand()%100; if( nRatio < pKey1->nSound_play_probability ) m_pOwner->StartSound( m_pOwner, pKey1->strSound.c_str(), *m_pOwner->GetPosition(), true, pKey1->nSoundVolume, false, pKey1->SoundOption ); } else { m_pOwner->StartSound( m_pOwner, pKey1->strSound.c_str(), *m_pOwner->GetPosition(), true, pKey1->nSoundVolume, false, pKey1->SoundOption ); } } } if( m_pEventHandle00_motion_effect ) { Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; m_pEventHandle00_motion_effect->GetData( eventTime, pKey1, pKey2 ); if( pKey1 && pKey1->bUse == false ) { pKey1->bUse = true; //사용. FX_DATA fxdata; fxdata.nFX_ID = pKey1->nFXsetID; fxdata.nEffPos = pKey1->nEffPos; fxdata.owner = m_pOwner->GetArID(); fxdata.attack = m_pOwner->GetArID(); fxdata.target = m_pOwner->GetArID(); fxdata.fPlayRate = pKey1->fPlayRate; fxdata.nPlayID = 0;//한번 fxdata.nMode = 0;//기본 m_pOwner->AddEffect( &fxdata ); } } _processEvent( m_pEventHandle01, eventTime ); _processEvent( m_pEventHandle02, eventTime ); _processEvent( m_pEventHandle03, eventTime ); _processEvent( m_pEventHandle04, eventTime ); _processEvent( m_pEventHandle05, eventTime ); _processEvent( m_pEventHandle06, eventTime ); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SWorkWarp SWorkWarp::SWorkWarp( class SGameAvatarEx * pOwner, struct SCMSG_WARP * pMsg ) : SGameWork( pOwner ) { // _oprint( "SWorkWarp::SWorkWarp\n" ); m_pWarpMsg = new SCMSG_WARP; m_pWarpMsg->x = pMsg->x; m_pWarpMsg->y = pMsg->y; m_pWarpMsg->z = pMsg->z; m_pWarpMsg->layer = pMsg->layer; } SWorkWarp::~SWorkWarp() { if( m_pOwner ) m_pOwner->InputThawing(); SAFE_DELETE( m_pWarpMsg ); } void SWorkWarp::Process( DWORD dwTime ) { // _oprint( "SWorkWarp::Process\n" ); m_pOwner->SetArObjectPos( m_pWarpMsg->x, m_pWarpMsg->y, m_pWarpMsg->z, m_pWarpMsg->layer ); float fHeight = 0.f; WORD wTile=0; m_pOwner->GetHeight(m_pWarpMsg->x,m_pWarpMsg->y,fHeight,wTile); m_pOwner->SetPosition( K3DVector(m_pWarpMsg->x,m_pWarpMsg->y, fHeight) ); SGameAvatarEx* pTransportCreature = (SGameAvatarEx*)m_pOwner->GetGameTransportCreatureObject( m_pOwner->GetCreatureMountHandle() ); if( pTransportCreature ) { m_pOwner->SetMountMode(); pTransportCreature->SetMountMode(); pTransportCreature->SetArObjectPos( m_pWarpMsg->x, m_pWarpMsg->y, m_pWarpMsg->z, m_pWarpMsg->layer ); pTransportCreature->SetPosition( K3DVector(m_pWarpMsg->x,m_pWarpMsg->y, fHeight) ); int nDefaultAniType; switch( pTransportCreature->GetCreatureMountType() ) { case SGameAvatarEx::RIDE_LOW_TYPE: nDefaultAniType = ANI_M_DEFAULT01_LOW; break; case SGameAvatarEx::RIDE_HIGH_TYPE: nDefaultAniType = ANI_M_DEFAULT01_HIGH; break; case SGameAvatarEx::RIDE_QILIN_TYPE: nDefaultAniType = ANI_M_DEFAULT01_QILIN; break; case SGameAvatarEx::RIDE_WHITE_TYPE: nDefaultAniType = ANI_M_DEFAULT01_WHITE; break; case SGameAvatarEx::RIDE_UNICORN_TYPE: nDefaultAniType = ANI_M_DEFAULT01_UNICORN; break; /// 2011.02.08 - prodongi case SGameAvatarEx::RIDE_BEAKHO_TYPE: nDefaultAniType = ANI_M_DEFAULT01_BEAKHO; break; default: nDefaultAniType = ANI_M_DEFAULT01_HIGH; break; } m_pOwner->NPlayAnimation( nDefaultAniType, SEQTYPE_LOOP ); pTransportCreature->NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); } else { //마운트 모드가 아닐때 기본 상태로 // if( !m_pOwner->IsMountMode() ) SGameAvatarEx* pCreature = (SGameAvatarEx*)m_pOwner->GetGameObject( m_pOwner->GetCreatureMountHandle() ); if( pCreature ) { pCreature->SetAniLock( false ); pCreature->Default(); } m_pOwner->SetAniLock( false ); m_pOwner->Default(); } m_pOwner->SetAttackAniLock( false ); m_pOwner->WarpComplete( m_pWarpMsg ); m_pOwner->InputThawing(); SetEnd( TRUE ); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SWorkAttack SWorkAttack::SWorkAttack( SGameAvatarEx * pOwner, K3DVector & targetpos, AR_HANDLE targetID, int nDamage, int nRest_hp, int nAttackMsec ) : SGameWork(pOwner) { // _oprint( "호호호 : SWorkAttack::SWorkAttack %0x8d \n", targetID ); m_TargetPos = targetpos; m_TargetID = targetID; m_nDamage = nDamage; m_nRest_hp = nRest_hp; m_nAttackMsec = nAttackMsec; } SWorkAttack::~SWorkAttack() { } void SWorkAttack::Process( DWORD dwTime ) { // _oprint( "SWorkAttack Damage : %d, RestHP : %d\n", m_nDamage, m_nRest_hp ); m_pOwner->SetViewVector( m_TargetPos ); // m_pOwner->SetDamage( m_TargetID, m_nDamage, m_nRest_hp ); // m_pOwner->Attack( m_TargetID, m_TargetPos, m_nAttackMsec ); SetEnd(TRUE); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SWorkGoodPosSearch SWorkGoodPosSearch::SWorkGoodPosSearch( class SGameAvatarEx * pOwner, AR_HANDLE hMaster ): SGameWork(pOwner) { // _oprint( "SWorkGoodPosSearch::SWorkGoodPosSearch\n" ); m_hMaster = hMaster; //주인님 SetStep(STEP_01); } SWorkGoodPosSearch::~SWorkGoodPosSearch() { } void SWorkGoodPosSearch::Process( DWORD dwTime ) { //성공 할때까지, 자동으로 해준다. //공격하는 Object에서 떨어진다. //적절한 위치라 함은, 어딜까??? } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SWorkPickUp::SWorkPickUp( class SGameAvatarEx * pOwner, class SGameAvatarEx* pItem ) : SGameWork(pOwner) { m_dwStartTime = 0; m_pOwner->SetViewVector( *pItem->GetPosition() ); SetStep( STEP_00 ); } SWorkPickUp::~SWorkPickUp() { } void SWorkPickUp::Process( DWORD dwTime ) { if( IsEnd() ) return; //마운트 상태에서는 줍기 모션 생략 if( m_pOwner->IsMountMode() ) { SetEnd( TRUE ); return; } if( m_dwStartTime == 0 ) m_dwStartTime = dwTime; if( !m_pOwner->IsMoving() ) { if( GetStep() == STEP_00 ) { m_dwStartTime = dwTime; m_pOwner->SetAniLock( false ); m_pOwner->PickUpEx(); m_pOwner->SetAniLock( true ); SetStep( STEP_01 ); } else if( GetStep() == STEP_01 ) { if( !m_pOwner->IsPlaying() && m_pOwner->GetCurrAnimationID() == ANI_PICKUP01 ) { m_pOwner->SetAniLock( false ); m_pOwner->StandUp(); SetEnd( TRUE ); } } //줍는 도중 이동 및 공격 모션으로 바뀌었을 경우 검사한다 if( m_pOwner->IsPlaying() && m_pOwner->GetCurrAnimationID() != ANI_PICKUP01 ) { m_pOwner->SetIng(false); m_pOwner->SetAniLock( false ); SetEnd( TRUE ); } } //10초가 경과했는데도 끝나지 않았다면 if( dwTime - m_dwStartTime > 10000 ) { //줍는 모션중이라면 if( m_pOwner->GetCurrAnimationID() == ANI_PICKUP01 ) { m_pOwner->StandUp(); } m_pOwner->SetIng(false); m_pOwner->SetAniLock( false ); SetEnd( TRUE ); } } ////////////////////////////////////////////////////////////////////////// SWorkAniSit::SWorkAniSit( class SGameAvatarEx * pOwner, DWORD dwTime ) : SGameWork(pOwner) { m_dwStartTime = dwTime; SetStep( STEP_00 ); } SWorkAniSit::~SWorkAniSit() { } void *SWorkAniSit::PerformMsg( struct SGameMessage * pMsg ) { return (void*)0; } void SWorkAniSit::Process( DWORD dwTime ) { //if( GetStep() != STEP_00 ) //{ // if( dwTime - m_dwStartTime > 3000 ) // { //3000 초 이후에는 강제 종료 // SetEnd( TRUE ); // } //} if( GetStep() == STEP_00 ) { m_dwStartTime = dwTime; m_pOwner->SetAniLock( false ); m_pOwner->SitProcess( ANI_SITDOWN ); m_pOwner->SetAniLock( true ); SetStep( STEP_01 ); } else if( GetStep() == STEP_01 ) { if( !m_pOwner->IsPlaying() && m_pOwner->GetCurrAnimationID() == ANI_SITDOWN ) { m_pOwner->SetIng(false); m_pOwner->SetAniLock( false ); m_pOwner->SitProcess( ANI_SIT, SEQTYPE_LOOP ); SetEnd( TRUE ); } else { if( dwTime - m_dwStartTime > 3000 ) SetEnd( TRUE ); } } } ////////////////////////////////////////////////////////////////////////// SWorkAniStandUp::SWorkAniStandUp( class SGameAvatarEx * pOwner, DWORD dwTime ) : SGameWork(pOwner) { m_dwStartTime = dwTime; SetStep( STEP_00 ); } SWorkAniStandUp::~SWorkAniStandUp() { } void SWorkAniStandUp::Process( DWORD dwTime ) { if( GetStep() == STEP_00 ) { m_pOwner->SitProcess( ANI_SITUP ); SetStep( STEP_01 ); } else if( GetStep() == STEP_01 ) { if( !m_pOwner->IsPlaying() && m_pOwner->GetCurrAnimationID() == ANI_SITUP ) { m_pOwner->SetAniLock( false ); m_pOwner->StandUp(); SetEnd( TRUE ); m_pOwner->SetIng(false); } } //2초 후에는 무조건 종료 if( (dwTime - m_dwStartTime) > 2000 ) { //일어서는 도중 애니메이션이 바뀌었는지 검사한다( 일어서는 도중 이동 및 공격 할수있기 때문 ) if( m_pOwner->GetCurrAnimationID() == ANI_SITUP ) { m_pOwner->StandUp(); } m_pOwner->SetAniLock( false ); SetEnd( TRUE ); m_pOwner->SetIng(false); } } ////////////////////////////////////////////////////////////////////////// SWorkAimingBow::SWorkAimingBow( class SGameAvatarEx * pOwner, AR_HANDLE hTarger, char bowtype ) : SGameWork(pOwner) { m_hTarget = hTarger; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd( TRUE ); return; } m_nTypeBow = 0; // Arrow casting and shooting effect IDs // 3049 Normal Arrow_Cast Asura (Female Only) // 3050 Normal Arrow_Cast Asura (Male Only) // 3051 Normal Arrow_Cast Deva (Female Only) // 3052 Normal Arrow_Cast Deva (Male Only) m_nEffectID[0] = -1; m_nEffectID[1] = -1; if( bowtype & TS_ATTACK_EVENT::ATTACK_FLAG_CROSS_BOW ) { m_strFX_01 = "rcfx_cross_arrowattack_start_lv01_"; m_strFX_02 = "rcfx_cross_arrowattack_loop_lv01_"; } else { m_strFX_01 = "rcfx_arrowattack_start_lv01_"; m_strFX_02 = "rcfx_arrowattack_loop_lv01_"; } const char* szName = GetNX3Name( pOwner->GetRace(), pOwner->GetSex() ); m_strFX_01 += szName; m_strFX_02 += szName; SetStep( STEP_00 ); SetWorkType( WORK_AIMINGBOW ); pOwner->SetVisibleWeaponTrail( true ); } SWorkAimingBow::~SWorkAimingBow() { if( m_pOwner ) { if( m_nEffectID[0] != -1 ) m_pOwner->DelEffect( m_nEffectID[0] ); if( m_nEffectID[1] != -1 ) m_pOwner->DelEffect( m_nEffectID[1] ); } } void SWorkAimingBow::ForceEnd() { m_bEnd = TRUE; if( m_nEffectID[0] != -1 ) m_pOwner->DelEffect( m_nEffectID[0] ); if( m_nEffectID[1] != -1 ) m_pOwner->DelEffect( m_nEffectID[1] ); } void SWorkAimingBow::Process( DWORD dwTime ) { if( IsEnd() ) return; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( m_pTarget == NULL ) { m_pOwner->SetIng(false); m_pOwner->SetAniLock( false ); m_pOwner->Default(); SetEnd( TRUE ); return; } m_pOwner->SetViewVector( *m_pTarget->GetPosition() ); //////////////////////////////////////////////////////////////////////////// if( GetStep() == STEP_00 ) { m_pOwner->SetIng(true); m_pOwner->SetAniLock( false ); m_pOwner->NPlayAnimation( ANI_BOW_ATTACK01_A ); //장전 m_nEffectID[0] = m_pOwner->AddEffect( &FX_DATA_EX( m_strFX_01.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true ) ); m_pOwner->SetAniLock( true ); SetStep( STEP_01 ); } else if( GetStep() == STEP_01 ) { if( !m_pOwner->IsPlaying() ) { m_pOwner->SetAniLock( false ); m_pOwner->NPlayAnimation( ANI_BOW_ATTACK01_B, SEQTYPE_LOOP ); //겨누기 m_nEffectID[1] = m_pOwner->AddEffect( &FX_DATA_EX( m_strFX_02.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true, SEQTYPE_LOOP ) ); m_pOwner->SetAniLock( true ); SetStep( STEP_04 ); } } //장전 및 겨누기 이외 모션이 재생될 경우 끝낸다 if( m_pOwner->GetCurrAnimationID() != ANI_BOW_ATTACK01_A && m_pOwner->GetCurrAnimationID() != ANI_BOW_ATTACK01_B ) { m_pOwner->SetIng(false); SetEnd(TRUE); } } ////////////////////////////////////////////////////////////////////////// SWorkShootingBow::SWorkShootingBow( class SGameAvatarEx * pOwner, AR_HANDLE hTarger, char bowtype ) : SGameWork(pOwner) { m_hTarget = hTarger; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd( TRUE ); return; } m_pAttackMsg = NULL; m_nTypeBow = 0; m_nEffectID = -1; m_strFX_03 = "rcfx_arrowattack_end_lv01_"; m_strFX_03 += GetNX3Name( pOwner->GetRace(), pOwner->GetSex() ); SetStep( STEP_00 ); SetWorkType( WORK_SHOOTINGBOW ); } SWorkShootingBow::~SWorkShootingBow() { SAFE_DELETE( m_pAttackMsg ); if( m_nEffectID != -1 ) { if( m_pOwner ) m_pOwner->DelEffect( m_nEffectID ); } } void SWorkShootingBow::SetDamegeInfo( const struct SStateInfo * pStateInfo ) { SAFE_DELETE( m_pAttackMsg ); SMSG_ATTACK * pAttackMsg = new SMSG_ATTACK; pAttackMsg->attacker_handle = pStateInfo->hSelf; pAttackMsg->target_handle = pStateInfo->hTarget; pAttackMsg->attack_action = pStateInfo->attack_action; pAttackMsg->attack_flag = pStateInfo->attack_flag; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); pAttackMsg->attack_speed = pStateInfo->dwSpeed; pAttackMsg->count = pStateInfo->count; for( int i = 0; i < pStateInfo->count; i++ ) { pAttackMsg->m_vAttackInfoList.push_back( pStateInfo->vAttackInfoList[i] ); } pAttackMsg->nTypeBow = m_nTypeBow; m_pAttackMsg = pAttackMsg; } bool SWorkShootingBow::ProcessingDamage() { if( GetStep() != STEP_02 ) return false; return true; } void SWorkShootingBow::Process( DWORD dwTime ) { // Fraun performance tweak if( IsEnd() ) return; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject(m_hTarget); if( m_pTarget == NULL ) { m_pOwner->SetIng(false); m_pOwner->SetAniLock(false); m_pOwner->Default(); SetEnd(TRUE); return; } int nCurrtStep = GetStep(); switch (nCurrtStep) { case STEP_00: { m_pOwner->SetViewVector(*m_pTarget->GetPosition()); // Shoot after the character’s direction has been set if (m_pAttackMsg && !m_pOwner->IsRotation()) { m_pOwner->SetIng(true); m_pOwner->SetAniLock(false); m_pOwner->NPlayAnimation(ANI_BOW_ATTACK01_C); // Shooting m_nEffectID = m_pOwner->AddEffect(&FX_DATA_EX(m_strFX_03.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true)); m_pOwner->SetAniLock(true); m_pOwner->AddAction(m_pAttackMsg); SetStep(STEP_02); } else { SetStep(STEP_01); } break; } case STEP_01: { if (m_pAttackMsg && !m_pOwner->IsRotation()) { m_pOwner->SetIng(true); m_pOwner->SetAniLock(false); m_pOwner->NPlayAnimation(ANI_BOW_ATTACK01_C); m_nEffectID = m_pOwner->AddEffect(&FX_DATA_EX(m_strFX_03.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true)); m_pOwner->SetAniLock(true); m_pOwner->AddAction(m_pAttackMsg); SetStep(STEP_02); } } case STEP_02: { if (!m_pOwner->IsPlaying()) { m_pOwner->SetIng(false); m_pOwner->SetAniLock(false); m_pOwner->Default(); // Return to the default pose SetEnd(TRUE); } } } // End if any motion other than the shooting motion is played if(GetStep() == STEP_02 && m_pOwner->GetCurrAnimationID() != ANI_BOW_ATTACK01_C ) { m_pOwner->SetIng(false); SetEnd(TRUE); } } //============================================================================================== //New Skill 시스템 SNewSkill::SNewSkill( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SGameWork( pOwner ), m_pSkillFX(pSkillFX) { // SetEnd( true ); m_fPlayRate = 1.f; //1배 m_fPlayRateAfterFire = 1.0f; m_hTarget = 0; m_pTarget = NULL; m_pEventSet = NULL; m_pDamage = NULL; m_pSkillEvent = NULL; m_nCurHitIndex = 0; m_nHitCnt = 0; m_dwStartTime = 0; m_nFireMotionID = pSkillFX->nFire_Motion_Id; m_nFxID = -1; //1이면 타겟형 //0이면 셀프형 if( m_pSkillFX->szHas_Target > 0 ) m_bIsSelfSkill = false; else m_bIsSelfSkill = true; m_dwCatingTime = 0; m_pActionSkillEvent = NULL; m_bIsMeleeSkill = false; } SNewSkill::~SNewSkill() { if(m_nFxID != -1) { if( m_pOwner ) m_pOwner->EndLoopFx(m_nFxID); } if( !m_vFX_List.empty() ) { if( m_pOwner ) { for( unsigned int i(0); m_vFX_List.size()>i; i++ ) m_pOwner->DelEffect(m_vFX_List[i]); } m_vFX_List.erase( m_vFX_List.begin(), m_vFX_List.end() ); } if( m_pOwner ) { //힛팅 처리 안된 것들 처리 m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( m_pTarget ) { while(m_nHitCnt > 0) _processDamage(); } } //Event handle 처리 if( m_pEventSet ) { m_pEventSet->event_clear(); SAFE_DELETE( m_pEventSet ); } SAFE_DELETE( m_pSkillEvent ); SAFE_DELETE( m_pDamage ); SAFE_DELETE( m_pSkillFX ); if( m_pActionSkillEvent ) { if( m_pOwner ) m_pOwner->AddAction( m_pActionSkillEvent ); SAFE_DELETE( m_pActionSkillEvent ); } } void SNewSkill::ForceEnd() { if(m_nFxID != -1) { m_pOwner->EndLoopFx(m_nFxID); } m_bEnd = TRUE; } void SNewSkill::SetDamegeInfo( const struct SStateInfo * pStateInfo ) { SAFE_DELETE( m_pSkillEvent ); SAFE_DELETE( m_pDamage ); //데미지 일반 데미지 때릴때 사용 m_pDamage = new SMSG_DAMAGE; m_pDamage->attacker_handle = pStateInfo->hSelf; m_pDamage->target_handle = pStateInfo->hTarget; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_pDamage->target_handle ); if( !m_pTarget ) { SetEnd(true); return; } SetDamageDisplayName( m_pDamage, m_pTarget ); //스킬 이벤트 -> Action 에 날릴때 사용 m_pSkillEvent = new SMSG_SKILL_EVENT; m_pSkillEvent->skill_id = pStateInfo->nSkillID; m_pSkillEvent->skill_level = pStateInfo->nSkillLv; m_pSkillEvent->caster = m_pOwner->GetArID(); m_pSkillEvent->target = pStateInfo->hTarget; m_pSkillEvent->fire.count = pStateInfo->nRepeat; m_pSkillEvent->fire.bMultiple = pStateInfo->bMultiple; m_pSkillEvent->fire.range = pStateInfo->range; m_pSkillEvent->fire.target_count = pStateInfo->target_count; m_pSkillEvent->fire.fire_count = pStateInfo->fire_count; m_pDamage->nSkillID = pStateInfo->nSkillID; m_pDamage->nSkillLevel = pStateInfo->nSkillLv; m_nCount = (int)pStateInfo->vSkillResult.size(); m_nCurHitIndex = 0; m_nHitCnt = m_nCount; //스킬 결과 데미지 for( unsigned int i(0); pStateInfo->vSkillResult.size()>i; i++ ) m_pSkillEvent->vSkillResult.push_back( pStateInfo->vSkillResult[i] ); _oprint( "Server skill result %d\n", pStateInfo->vSkillResult.size() ); } void SNewSkill::SetActionSkillEvent( const struct SStateInfo * pStateInfo ) { //스킬 이벤트 -> Action 에 날릴때 사용 m_pActionSkillEvent = new SMSG_SKILL_EVENT; m_pActionSkillEvent->status_type = TS_SC_SKILL::FIRE; m_pActionSkillEvent->skill_id = pStateInfo->nSkillID; m_pActionSkillEvent->skill_level = pStateInfo->nSkillLv; m_pActionSkillEvent->caster = m_pOwner->GetArID(); m_pActionSkillEvent->target = pStateInfo->hTarget; //m_pActionSkillEvent->target_name = pStateInfo->target_name; // Fraun performance tweak m_pActionSkillEvent->fire.count = pStateInfo->nRepeat; m_pActionSkillEvent->fire.bMultiple = pStateInfo->bMultiple; m_pActionSkillEvent->fire.range = pStateInfo->range; m_pActionSkillEvent->fire.target_count = pStateInfo->target_count; m_pActionSkillEvent->fire.fire_count = pStateInfo->fire_count; //스킬 결과 데미지 for( unsigned int i(0); pStateInfo->vSkillResult.size()>i; i++ ) m_pActionSkillEvent->vSkillResult.push_back( pStateInfo->vSkillResult[i] ); } void SNewSkill::SetTarget( AR_HANDLE handle, class SGameAvatarEx* pTarget ) { m_hTarget = handle; m_pTarget = pTarget; } void SNewSkill::SetSkillMode( SKILL_MODE bMode ) { m_nMode = bMode; if( m_nMode == SKILLMODE_CAST ) { _processView(); } } void SNewSkill::SetPlayRate( float fPlayRate ) { m_fPlayRate = fPlayRate; } void SNewSkill::SetStartTime( DWORD dwStartTime ) { m_dwStartTime = dwStartTime; } void SNewSkill::SetFireMotionID( int nFireMotionID ) { m_nFireMotionID = nFireMotionID; } void SNewSkill::SetCastingTime( DWORD time ) { m_dwCatingTime = time; } bool SNewSkill::ProcessingDamage() { if( m_nHitCnt > 0 || GetSkillMode() != SKILLMODE_FIRE ) return false; return true; } void SNewSkill::_processDamage() { if( m_nHitCnt > 0 ) { m_pDamage->skillresult = m_pSkillEvent->vSkillResult[m_nCount - m_nHitCnt]; if( m_pTarget ) { int nBlock = 0; int nCritical = 0; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_CRITICAL) nCritical = 1; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_BLOCK) nBlock = 1; m_pOwner->OnDamage( m_pOwner->GetArID(), m_pTarget->GetArID(), m_pDamage ); std::string strScript; int resultType = m_pDamage->skillresult.GetType(); if( (resultType == SkillResult::DAMAGE || resultType == SkillResult::MAGIC_DAMAGE || resultType == SkillResult::CHAIN_DAMAGE || resultType == SkillResult::CHAIN_MAGIC_DAMAGE) && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { m_pTarget->Damage(); // Fraun performance tweak (TODO: return it back; testing purposes!) //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), m_pTarget->GetArID(), nCritical, nBlock ); } else if( m_pDamage->skillresult.GetType() == SkillResult::DAMAGE_WITH_KNOCK_BACK && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { if( m_pTarget->GetHP() > 0 ) { m_pTarget->SetAniLock( false ); m_pTarget->NPlayAnimation( ANI_DAMAGE01, SEQTYPE_LOOP ); } K3DVector vKnockBackPosition = K3DVector( m_pDamage->skillresult.damage_kb.x, m_pDamage->skillresult.damage_kb.y, 0.f ); m_pTarget->SetKnockBack( vKnockBackPosition , m_pDamage->skillresult.damage_kb.speed ); m_pTarget->Damage(); // Fraun performance tweak (TODO: return it back; testing purposes!) //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), m_pTarget->GetArID(), nCritical, nBlock ); } // Fraun performance tweak (TODO: return it back; testing purposes!) //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); } --m_nHitCnt; } } void SNewSkill::_processDamageMulti() { if( m_nHitCnt > 0 ) { m_pDamage->skillresult = m_pSkillEvent->vSkillResult[m_nCount - m_nHitCnt]; SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_pDamage->skillresult.GetTargetHandle() ); if( pTarget ) { int nBlock = 0; int nCritical = 0; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_CRITICAL) nCritical = 1; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_BLOCK) nBlock = 1; m_pOwner->OnDamage( m_pOwner->GetArID(), pTarget->GetArID(), m_pDamage ); std::string strScript; if( (m_pDamage->skillresult.GetType() == SkillResult::DAMAGE || m_pDamage->skillresult.GetType() == SkillResult::MAGIC_DAMAGE) && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { pTarget->Damage(); XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), pTarget->GetArID(), nCritical, nBlock ); } else if( m_pDamage->skillresult.GetType() == SkillResult::DAMAGE_WITH_KNOCK_BACK && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { if( pTarget->GetHP() > 0 ) { pTarget->SetAniLock( false ); pTarget->NPlayAnimation( ANI_DAMAGE01, SEQTYPE_LOOP ); } K3DVector vKnockBackPosition = K3DVector( m_pDamage->skillresult.damage_kb.x, m_pDamage->skillresult.damage_kb.y, 0.f ); pTarget->SetKnockBack( vKnockBackPosition , m_pDamage->skillresult.damage_kb.speed ); pTarget->Damage(); // Fraun performance tweak (TODO: return it back; testing purposes!) //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), pTarget->GetArID(), nCritical, nBlock ); } // Fraun performance tweak (TODO: return it back; testing purposes!) //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); } --m_nHitCnt; } } void SNewSkill::Process( DWORD dwTime ) { m_dwTime = dwTime; if( IsEnd() ) return; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } if( GetSkillMode() == SKILLMODE_CAST ) { _processDefCast( dwTime ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { _processDefFire( dwTime ); } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } void SNewSkill::_processEventSet( DWORD eventTime ) { if( !m_pEventSet ) return; if( m_pEventSet->pCurEvent00_effect ) { //시작 되자 마자 나오는 Effect Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; m_pEventSet->pCurEvent00_effect->GetData( 0, pKey1, pKey2 ); if( pKey1 && !pKey1->bUse ) { pKey1->bUse = true; m_pOwner->FindMotionAddOnFx( pKey1 ); switch(pKey1->nSpeedType) { case 0: { float fPlayRate = m_pOwner->GetCurPlayRate(); m_pOwner->AddEffect( &FX_DATA_EX( pKey1->strEffect.c_str(), pKey1->followflag, m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), pKey1->nEffPos, false, pKey1->nSpeedType, fPlayRate ) ); } break; case 2: { if(!pKey1->strEffect.empty()) { float fPlayRate = m_pOwner->GetCurPlayRate(); m_pOwner->AddEffect( &FX_DATA_EX( pKey1->strEffect.c_str(), pKey1->followflag, m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), pKey1->nEffPos, false, pKey1->nSpeedType, fPlayRate ) ); } //검 잔상 m_pOwner->ActivateFxSwordSlashForSkill(); } break; } } } if( m_pEventSet->pCurEvent00_sound ) { Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; m_pEventSet->pCurEvent00_sound->GetData( eventTime, pKey1, pKey2 ); if( pKey1 && !pKey1->bUse ) { pKey1->bUse = true; if( pKey1->nSound_play_probability != 100 ) { int nRatio = rand()%100; if( nRatio < pKey1->nSound_play_probability ) m_pOwner->StartSound( m_pOwner, pKey1->strSound.c_str(), *m_pOwner->GetPosition(), true, pKey1->nSoundVolume, false, pKey1->SoundOption ); } else { m_pOwner->StartSound( m_pOwner, pKey1->strSound.c_str(), *m_pOwner->GetPosition(), true, pKey1->nSoundVolume, false, pKey1->SoundOption ); } } } if( m_pEventSet->pCurEvent00_motion_effect ) { Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; m_pEventSet->pCurEvent00_motion_effect->GetData( eventTime, pKey1, pKey2 ); if( pKey1 && pKey1->bUse == false ) { pKey1->bUse = true; //사용. FX_DATA fxdata; fxdata.nFX_ID = pKey1->nFXsetID; fxdata.nEffPos = pKey1->nEffPos; fxdata.owner = m_pOwner->GetArID(); fxdata.attack = m_pOwner->GetArID(); fxdata.target = m_pOwner->GetArID(); fxdata.fPlayRate = pKey1->fPlayRate; fxdata.nPlayID = 0;//한번 fxdata.nMode = 0;//기본 m_pOwner->AddEffect( &fxdata ); } } if( GetSkillMode() == SKILLMODE_CAST ) return; // _processEvent( , eventTime ); // _processEvent( , eventTime ); _processEvent( m_pEventSet->pCurEvent01 , eventTime ); _processEvent( m_pEventSet->pCurEvent02 , eventTime ); _processEvent( m_pEventSet->pCurEvent03 , eventTime ); _processEvent( m_pEventSet->pCurEvent04 , eventTime ); _processEvent( m_pEventSet->pCurEvent05 , eventTime ); _processEvent( m_pEventSet->pCurEvent06 , eventTime ); } void SNewSkill::_processEvent( KEventKeyRes* event, DWORD eventTime ) { if( event ) { Key_EVENT_NEW * pKey1 = NULL; Key_EVENT_NEW * pKey2 = NULL; event->GetData( eventTime, pKey1, pKey2 ); if( pKey1 && !pKey1->bUse ) { pKey1->bUse = true; std::string strScript; //힛팅임. if( pKey1->nHandleID == SMotionEventHanderDB::EV_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_LEFT_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_RIGHT_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_TWO_HAND_HIT ) { assert( GetSkillMode() != SKILLMODE_CAST && "캐스팅 모션에 힛팅 연출 모션이 설정 되어 있음." ); OnEventHit(); } else if( pKey1->nHandleID == SMotionEventHanderDB::EV_SHOOT || pKey1->nHandleID == SMotionEventHanderDB::EV_SWING ) { // 이것도 따로 처리해야 해야 할듯 OnEventSwing(); XStringUtil::Format( strScript, "%s( %u, %u )", "call_fx_ch_weapone_attack", m_pOwner->GetArID(), m_pTarget->GetArID() ); } else { if( pKey1->nHandleID != 0 ) { _MOTION_EVENT_HANDER * pHandler = GetMotionEventHanderDB().GetScript( pKey1->nHandleID ); if( pHandler ) { OnEventEtc(); XStringUtil::Format( strScript, "%s( %u )", pHandler->szScript, m_pOwner->GetArID(), m_pTarget->GetArID() ); } } } if( pKey1->nHandleID == SMotionEventHanderDB::EV_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_LEFT_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_RIGHT_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_TWO_HAND_HIT || pKey1->nHandleID == SMotionEventHanderDB::EV_SHOOT ) { //이펙트 출력 if( GetSkillMode() == SKILLMODE_FIRE ) { if( m_pActionSkillEvent ) { if( m_pOwner->GetObjType() != TS_ENTER::GAME_MOB ) assert( false ); m_pOwner->AddAction( m_pActionSkillEvent ); SAFE_DELETE( m_pActionSkillEvent ); } } } // Fraun performance tweak (TODO: return it back; testing purposes!) //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); } } } void SNewSkill::_getEventSet() { //Ani 변경 되어서, 시작 시간 다시 설정 m_dwStartTime = m_dwTime; //Event handle 처리 if( m_pEventSet ) { m_pEventSet->event_clear(); SAFE_DELETE( m_pEventSet ); } m_pEventSet = new EVENT_SET; EVENT_SET event_set; m_pOwner->GetCurSeqEvent( event_set ); _setEvent( event_set.pCurEvent00_effect, m_pEventSet->pCurEvent00_effect ); _setEvent( event_set.pCurEvent00_sound , m_pEventSet->pCurEvent00_sound ); _setEvent( event_set.pCurEvent00_motion_effect, m_pEventSet->pCurEvent00_motion_effect ); _setEvent( event_set.pCurEvent01, m_pEventSet->pCurEvent01 ); _setEvent( event_set.pCurEvent02, m_pEventSet->pCurEvent02 ); _setEvent( event_set.pCurEvent03, m_pEventSet->pCurEvent03 ); _setEvent( event_set.pCurEvent04, m_pEventSet->pCurEvent04 ); _setEvent( event_set.pCurEvent05, m_pEventSet->pCurEvent05 ); _setEvent( event_set.pCurEvent06, m_pEventSet->pCurEvent06 ); } void SNewSkill::_processDefCast( DWORD dwTime ) { if( GetStep() == STEP_00 ) { //손 올리기 if( m_pSkillFX->nCasting_Start_Motion_Id != 0 ) { m_pOwner->NPlayAnimation( m_pSkillFX->nCasting_Start_Motion_Id, SEQTYPE_NORMAL, m_fPlayRate*4.8f ); _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nCasting_Fx_Set_Id, EFFECT_POS_BOTTOM, SEQTYPE_LOOP ); _getEventSet(); } // m_pOwner->OnSkillDamage( m_pOwner->GetArID(), m_pOwner->GetArID(), ) SetStep(STEP_01); } else if( GetStep() == STEP_01 ) { //손 올리고 대기 if( m_pSkillFX->nCasting_Start_Motion_Id != 0 ) { if( m_pOwner->GetCurrAnimationID() == m_pSkillFX->nCasting_Start_Motion_Id && !m_pOwner->IsPlaying() ) { //밀리스킬과 마법스킬을 구분해서 마법스킬만 skill_b를 루프 if (m_bIsMeleeSkill) m_pOwner->NPlayAnimation( m_pSkillFX->nCasting_Middle_Motion_Id, SEQTYPE_NORMAL, m_fPlayRate*4.8 ); else m_pOwner->NPlayAnimation( m_pSkillFX->nCasting_Middle_Motion_Id, SEQTYPE_LOOP, 4.8f ); // _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nCasting_Fx_Set_Id, EFFECT_POS_BOTTOM, SEQTYPE_LOOP ); _getEventSet(); SetStep(STEP_02); } } else if( m_pSkillFX->nCasting_Start_Motion_Id == 0 ) { if( m_pSkillFX->nCasting_Middle_Motion_Id != 0 ) { //밀리스킬과 마법스킬을 구분해서 마법스킬만 skill_b를 루프 if (m_bIsMeleeSkill) m_pOwner->NPlayAnimation( m_pSkillFX->nCasting_Middle_Motion_Id, SEQTYPE_NORMAL, m_fPlayRate*4.8 ); else m_pOwner->NPlayAnimation( m_pSkillFX->nCasting_Middle_Motion_Id, SEQTYPE_LOOP, 4.8f ); if( m_nFxID == -1 ) _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nCasting_Fx_Set_Id, EFFECT_POS_BOTTOM, SEQTYPE_LOOP ); _getEventSet(); } SetStep(STEP_02); } } else if( GetStep() == STEP_02 ) { if( m_bIsMeleeSkill && !m_pOwner->IsPlaying() ) { if (m_nFireMotionID != 0) { m_pOwner->NPlayAnimation( m_nFireMotionID , SEQTYPE_NORMAL, m_fPlayRateAfterFire * 4.8f ); if( m_pSkillFX->nFire_Fx_Set_Id != 0 ) _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nFire_Fx_Set_Id , EFFECT_POS_BOTTOM, SEQTYPE_NORMAL ); _oprint("강제로 fire애니 재생\n"); } } // SetEnd(TRUE); } } void SNewSkill::_processDefFire( DWORD dwTime ) { if( GetStep() == STEP_00 ) { _oprint("Fire animation started: %d\n", m_nFireMotionID); if( m_nFireMotionID != 0 ) { if ( m_bIsMeleeSkill && m_pOwner->IsPlaying() && (m_pOwner->GetCurrAnimationID() == m_nFireMotionID)) { // 밀리스킬이고 재생중이고 재생중인게 파이어모션이면 } // 아무것도 하지않음 else if (m_nFireMotionID == ANI_ATTACK01) { // 스킬이지만 평타모션으로 나가고 있을 경우도 아무것도 하지 않음 } else // 아니면 파이어모션 출력 { m_pOwner->NPlayAnimation( m_nFireMotionID , SEQTYPE_NORMAL, m_fPlayRateAfterFire * 4.8f ); //시전시 동반 되는 이펙트 if( m_pSkillFX->nFire_Fx_Set_Id != 0 ) _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nFire_Fx_Set_Id , EFFECT_POS_BOTTOM, SEQTYPE_NORMAL ); } _getEventSet(); } SetStep(STEP_01); } else if( GetStep() == STEP_01 ) { if( m_nFireMotionID != 0 ) { if( m_pOwner->GetCurrAnimationID() == m_nFireMotionID && !m_pOwner->IsPlaying() ) { //시전 연출 끝났음. SetStep(STEP_02); } } else if( m_nFireMotionID == 0 ) { //시전 모션 없음. SetStep(STEP_02); } } else if( GetStep() == STEP_02 ) { m_pOwner->EndUseSkill( m_pSkillFX->nID ); m_pOwner->Default(); SetEnd(TRUE); } //이미 스킬이 완료 되었고 if( m_pOwner->IsUseSkill_complete() == true ) { //기존 애니메이션이 다르면, 종료 if( m_nFireMotionID != 0 && m_pOwner->GetCurrAnimationID() != m_nFireMotionID ) { _oprint( "Fire ended because the animation was different. [cur:%d] [fire:%d]\n", m_pOwner->GetCurrAnimationID(), m_nFireMotionID ); SetEnd( TRUE ); return; } } } // AziaMafia FixSkill void SNewSkill::_processView() { if (IsEnd()) return; if (m_pTarget && !m_bIsSelfSkill) { if (m_pTarget->GetArID() != m_pOwner->GetArID()) { if (GetSkillMode() == SKILLMODE_FIRE && m_pOwner->GetCurrAnimationID() != m_nFireMotionID) return; m_pOwner->SetViewVector(*m_pTarget->GetPosition()); } else m_bIsSelfSkill = true; } } void SNewSkill::_addEffect( const AR_HANDLE & owner, const AR_HANDLE & attack, const AR_HANDLE & target, const int & nFX_ID, const int & nFX_pos, int nAnitype, float fPlayRate ) { FX_DATA fx_data; fx_data.owner = owner; fx_data.attack = attack; fx_data.target = target; fx_data.nFX_ID = nFX_ID; //시전(타격)연출 보조FX ID fx_data.nEffPos = nFX_pos; //시전(타격)연출 보조FX 위치 fx_data.fPlayRate = fPlayRate; if(nAnitype == SEQTYPE_LOOP ) fx_data.bIsLoop = true; m_nFxID = m_pOwner->AddEffect( &fx_data ); } void SNewSkill::_addEffect( const AR_HANDLE & target, const int & nFX_ID, const int & nFX_pos ) { FX_DATA fx_data; fx_data.owner = target; fx_data.attack = target; fx_data.target = target; fx_data.nFX_ID = nFX_ID; //시전(타격)연출 보조FX ID fx_data.nEffPos = nFX_pos; //시전(타격)연출 보조FX 위치 m_nFxID = m_pTarget->AddEffect( &fx_data ); } void SNewSkill::_addFX( int nStage_Type ) { if( nStage_Type == SS_TYPE_121 ) { if( m_pSkillFX->fStage_Data[7] == 0 ) return; _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pTarget->GetArID(), m_pSkillFX->fStage_Data[7], m_pSkillFX->fStage_Data[8], SEQTYPE_NORMAL, m_pSkillFX->fStage_Data[1]*4.8f ); } else if( nStage_Type == SS_TYPE_122 ) { if( m_pSkillFX->fStage_Data[2] == 0 ) return; _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pTarget->GetArID(), m_pSkillFX->fStage_Data[2], m_pSkillFX->fStage_Data[3], SEQTYPE_NORMAL, m_pSkillFX->fStage_Data[1]*4.8f ); if( m_pSkillFX->fStage_Data[4] == 0 ) return; _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pTarget->GetArID(), m_pSkillFX->fStage_Data[4], m_pSkillFX->fStage_Data[5], SEQTYPE_NORMAL, m_pSkillFX->fStage_Data[1]*4.8f ); } else if( nStage_Type == SS_TYPE_123 ) { if( m_pSkillFX->fStage_Data[7] == 0 ) return; _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->fStage_Data[7], m_pSkillFX->fStage_Data[8], SEQTYPE_NORMAL, m_pSkillFX->fStage_Data[1]*4.8f ); } else if( nStage_Type == SS_TYPE_171) { if( m_pSkillFX->fStage_Data[7] == 0 ) return; _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pTarget->GetArID(), m_pSkillFX->fStage_Data[7], m_pSkillFX->fStage_Data[8], SEQTYPE_NORMAL, m_pSkillFX->fStage_Data[1]*4.8f ); } } float SNewSkill::CalcCurrentAniTimeTime( SGameAvatarEx* pAvatar ) { if( pAvatar == NULL ) return 0.0f; int nBoneCnt = 0; DWORD dwMinTime = 0, dwMaxTime = 0; DWORD dwCurAniTime = 0; pAvatar->GetCurrentAnimationInfo( nBoneCnt, dwMinTime, dwMaxTime, dwCurAniTime ); float fMaxTime = (float)dwMaxTime / 160.0f; float fMinTime = (float)dwMinTime / 160.0f; fMaxTime = ((fMaxTime * 4.8f) / 100.0f ) * 1000.0f; fMinTime = ((fMinTime * 4.8f) / 100.0f ) * 1000.0f; return fMaxTime - fMinTime; } //============================================================================================== //추후에 소환 연출 개개별로 만들 필요 있음. SWorkSummonCall::SWorkSummonCall( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { //마법 모션임. pSkillFX->nCasting_Start_Motion_Id; //시작 pSkillFX->nCasting_Middle_Motion_Id; //대기 pSkillFX->nFire_Motion_Id; //시전 SetStep(STEP_00); // 2010.08.31 - prodongi m_nFXID = -1; } SWorkSummonCall::~SWorkSummonCall() { // 2010.08.31 - prodongi //if( m_nFXID != 0 ) if( m_nFXID != 0 && -1 != m_nFXID) { if( m_pOwner ) m_pOwner->EndOtherEffect( m_nFXID ); } } void SWorkSummonCall::Process( DWORD dwTime ) { if( IsEnd() ) return; if( GetStep() == STEP_00 && GetSkillMode() == SKILLMODE_CAST ) { int fxid = 5081; m_nFXID = m_pOwner->AddOtherEffect( SGameOtherEffectMng::FX_CAST_SUMMONING_CREATURE, &OtherFxData( m_pOwner->GetArID(), 0,fxid, m_dwCatingTime, &m_vPos ) ); } else if( GetStep() == STEP_00 && GetSkillMode() == SKILLMODE_FIRE ) { // 2010.08.31 소환 주문서 사용 경우에 캐스팅 시간이 0이므로 SKILLMODE_CAST에 들어가지 않아서 이펙트가 출력 안될때가 만다 // 그래서 SKILLMODE_FIRE에서 출력하도록 해줌 - prodongi if (-1 == m_nFXID && 0 == m_dwCatingTime) { AR_HANDLE handle = m_pOwner->GetArID(); FX_DATA fx_data; fx_data.attack = handle; fx_data.owner = handle; fx_data.target = handle; fx_data.fPlayRate = 1.f; fx_data.nEffPos = EFFECT_POS_BOTTOM; fx_data.nPlayID = 0; fx_data.nFX_ID = 5081; m_pOwner->AddEffect(&fx_data); m_nFXID = 0; } m_pOwner->OnUISync( m_pOwner->GetArID(), m_pOwner->GetArID() ); } SNewSkill::Process( dwTime ); m_pOwner->SetViewVector( m_vPos ); } //============================================================================================== //추후에 역소환 연출 개개별로 만들 필요 있음. SWorkSummonReCall::SWorkSummonReCall( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { //마법 모션임. pSkillFX->nCasting_Start_Motion_Id; //시작 pSkillFX->nCasting_Middle_Motion_Id; //대기 pSkillFX->nFire_Motion_Id; //시전 } SWorkSummonReCall::~SWorkSummonReCall() { } void SWorkSummonReCall::Process( DWORD dwTime ) { if( IsEnd() ) return; if( GetStep() == STEP_00 && GetSkillMode() == SKILLMODE_FIRE ) { m_pOwner->OnUISync( m_pOwner->GetArID(), m_pOwner->GetArID() ); } SNewSkill::Process( dwTime ); } //============================================================================================== SWorkWeaponSwingHit::SWorkWeaponSwingHit( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { //물리 스킬 // pSkillFX->nCasting_Start_Motion_Id; //시작 // pSkillFX->nCasting_Middle_Motion_Id; //대기 // pSkillFX->nFire_Motion_Id; //시전 if( m_pSkillFX->fStage_Data[0] == 0 ) m_bMultiAttack = false; else m_bMultiAttack = true; SetStep(STEP_00); } SWorkWeaponSwingHit::~SWorkWeaponSwingHit() { if( m_pOwner ) { //처리가 안됐다면 if( m_bMultiAttack ) { while( m_nHitCnt > 0 ) //_processDamageMulti() 여기서 --m_nHitCnt 무조건 수행하므로 무한 루프 가능성은 없음 { _processDamageMulti(); } } } } void SWorkWeaponSwingHit::OnEventHit() { /// 2010.10.07 epic6에서 적용 안된 것 추가 /* //대상 1 if( !m_bMultiAttack ) { _processDamage(); } else //광역 { while( m_nHitCnt > 0 ) //_processDamageMulti() 여기서 --m_nHitCnt 무조건 수행하므로 무한 루프 가능성은 없음 { _processDamageMulti(); } } */ if( m_bMultiAttack ) _processDamage(); else { while( m_nHitCnt > 0 ) //_processDamageMulti() 여기서 --m_nHitCnt 무조건 수행하므로 무한 루프 가능성은 없음 { _processDamageMulti(); } } } void SWorkWeaponSwingHit::OnEventSwing() { } void SWorkWeaponSwingHit::OnEventEtc() { } /// 2010.10.07 epic6에서 적용 안되서 추가함 - prodongi /* void SWorkWeaponSwingHit::_processDamage() { if( m_pTarget ) { if( m_pSkillFX->nHit_Fx_Set_Id != 0 ) _addEffect( m_pTarget->GetArID(), m_pTarget->GetArID(), m_pTarget->GetArID(), m_pSkillFX->nHit_Fx_Set_Id, m_pSkillFX->nHit_Fx_Set_Position_Id ); } SNewSkill::_processDamage(); } */ void SWorkWeaponSwingHit::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkShieldSwingHit::SWorkShieldSwingHit( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { //물리 스킬 pSkillFX->nCasting_Start_Motion_Id; //시작 pSkillFX->nCasting_Middle_Motion_Id; //대기 pSkillFX->nFire_Motion_Id; //시전 if( m_pSkillFX->fStage_Data[0] == 0 ) m_bMultiAttack = false; else m_bMultiAttack = true; } SWorkShieldSwingHit::~SWorkShieldSwingHit() { if( m_pOwner ) { //처리가 안됐다면 if( m_bMultiAttack ) { while( m_nHitCnt > 0 ) //_processDamageMulti() 여기서 --m_nHitCnt 무조건 수행하므로 무한 루프 가능성은 없음 { _processDamageMulti(); } } else _processDamage(); } } void SWorkShieldSwingHit::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } void SWorkShieldSwingHit::OnEventHit() { //대상 1 if( !m_bMultiAttack ) { _processDamage(); } else //광역 { while( m_nHitCnt > 0 ) //_processDamage() 여기서 --m_nHitCnt 무조건 수행하므로 무한 루프 가능성은 없음 { _processDamageMulti(); } } } void SWorkShieldSwingHit::OnEventSwing() { } void SWorkShieldSwingHit::OnEventEtc() { } //============================================================================================== //스킬 연출 유형 121 SWorkWeaponSwing_3Motion::SWorkWeaponSwing_3Motion( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { int nFX1 = pSkillFX->fStage_Data[0];//모션배분 (0:순차 1:랜덤) int nFX2 = pSkillFX->fStage_Data[1];//모션속도변화 (1=100%, 클수록 빨라짐) int nFX3 = pSkillFX->fStage_Data[2];//시전(타격)모션1 ID int nFX4 = pSkillFX->fStage_Data[3];//시전(타격)모션2 ID int nFX5 = pSkillFX->fStage_Data[4];//시전(타격)모션3 ID int nFX6 = pSkillFX->fStage_Data[5];//시전(타격)연출 보조FX ID int nFX7 = pSkillFX->fStage_Data[6];//시전(타격)연출 보조FX 위치 m_fPlayRate = pSkillFX->fStage_Data[1]; //재생 배속 // m_nLocalFireMotionID[0] = pSkillFX->fStage_Data[2]; // m_nLocalFireMotionID[1] = pSkillFX->fStage_Data[3]; // m_nLocalFireMotionID[2] = pSkillFX->fStage_Data[4]; m_nCurHitCount = 0; m_cMaxHitCount = (int)pSkillFX->fStage_Data[9]; if( m_cMaxHitCount <= 0 ) m_cMaxHitCount = 3; m_pLocalFireMotionID = new int[m_cMaxHitCount]; for( unsigned char cMaxHitCount = 0; cMaxHitCount < m_cMaxHitCount; ++cMaxHitCount ) m_pLocalFireMotionID[cMaxHitCount] = pSkillFX->fStage_Data[2+cMaxHitCount]; //시전(타격)모션 } SWorkWeaponSwing_3Motion::~SWorkWeaponSwing_3Motion() { if( m_pOwner ) { m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( m_pTarget ) { while(m_nHitCnt > 0) _processDamage(); } } SAFE_DELETE_ARRAY( m_pLocalFireMotionID ); } void SWorkWeaponSwing_3Motion::OnEventHit() { _processDamage(); } void SWorkWeaponSwing_3Motion::OnEventSwing() { // _oprint( "스윙 이벤트\n" ); } void SWorkWeaponSwing_3Motion::OnEventEtc() { // _oprint( "그외 이벤트\n" ); } bool SWorkWeaponSwing_3Motion::ProcessingDamage() { //마지막 연타가 m_nCurHitCount == 2 //히트 카운트가 m_nHitCnt == 0 //SkillMode는 GetSkillMode() == SKILLMODE_FIRE if( m_nCurHitCount != 2 || m_nHitCnt > 0 || GetSkillMode() != SKILLMODE_FIRE ) return false; return true; } void SWorkWeaponSwing_3Motion::_processDamage() { //타겟 만큼 순차적으로 데미지 처리 for( unsigned char target_count = 0; target_count < m_pSkillEvent->fire.target_count; ++target_count ) { if( m_nHitCnt > 0 ) { m_pDamage->skillresult = m_pSkillEvent->vSkillResult[m_nCount - m_nHitCnt]; SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_pDamage->skillresult.GetTargetHandle() ); if( pTarget ) { int nBlock = 0; int nCritical = 0; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_CRITICAL) nCritical = 1; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_BLOCK) nBlock = 1; m_pOwner->OnDamage( m_pOwner->GetArID(), pTarget->GetArID(), m_pDamage ); if( (m_pDamage->skillresult.GetType() == SkillResult::DAMAGE || m_pDamage->skillresult.GetType() == SkillResult::MAGIC_DAMAGE) && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { pTarget->Damage(); // Fraun performance tweak (TODO: return it back; testing purposes!) //std::string strScript; //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), pTarget->GetArID(), nCritical, nBlock ); //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); if( m_pSkillFX->nSub_Fire_Fx_Set_Id != 0 ) _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nSub_Fire_Fx_Set_Id, m_pSkillFX->nSub_Fire_Fx_Position ); if( m_pSkillFX->nHit_Fx_Set_Id != 0 ) _addEffect( pTarget->GetArID(), pTarget->GetArID(), pTarget->GetArID(), m_pSkillFX->nHit_Fx_Set_Id, m_pSkillFX->nHit_Fx_Set_Position_Id ); } } --m_nHitCnt; } } } void SWorkWeaponSwing_3Motion::SetCurHitCount( int nCurHitCount ) { m_nCurHitCount = nCurHitCount; } void SWorkWeaponSwing_3Motion::Process( DWORD dwTime ) { if( IsEnd() ) return; m_dwTime = dwTime; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } _processView(); if( GetSkillMode() == SKILLMODE_CAST ) { if( GetStep() == STEP_00 ) { _addFX( m_pSkillFX->nStage_Type_Id ); } _processDefCast( dwTime ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { if( GetStep() == STEP_00 ) { if( m_nCurHitCount < m_cMaxHitCount && m_pLocalFireMotionID[m_nCurHitCount] != 0 ) { m_pOwner->NPlayAnimation( m_pLocalFireMotionID[m_nCurHitCount], SEQTYPE_NORMAL, m_fPlayRate * 4.8f ); _getEventSet(); if( m_nCurHitCount == 0 ) _addFX( m_pSkillFX->nStage_Type_Id ); SetStep( STEP_01 ); } else { m_pOwner->EndUseSkill( m_pSkillFX->nID ); m_pOwner->Default(); SetEnd(TRUE); return; } } else if( GetStep() == STEP_01 ) { int nAniType = m_pOwner->GetCurrAnimationID(); if( !m_pOwner->IsPlaying() || !CurrentlyAnimationIsFire() ) { m_pOwner->EndUseSkill( m_pSkillFX->nID ); m_pOwner->Default(); SetEnd(TRUE); return; } } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } bool SWorkWeaponSwing_3Motion::CurrentlyAnimationIsFire() { int nCurrentAniID = m_pOwner->GetCurrAnimationID(); for( unsigned char cMaxHitCount = 0; cMaxHitCount < m_cMaxHitCount; ++cMaxHitCount ) { if( nCurrentAniID == m_pLocalFireMotionID[cMaxHitCount] ) return true; } return false; } //============================================================================================== //스킬 연출 유형 122 SWorkWeaponSwing_ContinuousHits::SWorkWeaponSwing_ContinuousHits( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { m_nFireMotionID = pSkillFX->fStage_Data[0]; //시전모션 ID m_nEndFireMotionID = pSkillFX->fStage_Data[6]; m_fPlayRate = pSkillFX->fStage_Data[1]; //모션속도변화 (1=100%, 클수록 빨라짐) //pSkillFX->nStage_Data_03; //pSkillFX->nStage_Data_04; //pSkillFX->nStage_Data_05;//시전(타격)연출 보조FX(2) ID //pSkillFX->nStage_Data_06;//시전(타격)연출 보조FX(2) 위치 } SWorkWeaponSwing_ContinuousHits::~SWorkWeaponSwing_ContinuousHits() { if( m_pOwner ) { m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( m_pTarget ) { while(m_nHitCnt > 0) _processDamage(); } } } //Snewskill에서 처리 하지 말고 여기서 처리한다 ( 추가될수 있으이 ) bool SWorkWeaponSwing_ContinuousHits::ProcessingDamage() { if( m_nHitCnt > 0 || GetSkillMode() != SKILLMODE_FIRE ) return false; return true; } void SWorkWeaponSwing_ContinuousHits::Process( DWORD dwTime ) { if( IsEnd() ) return; m_dwTime = dwTime; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } _processView(); if( GetSkillMode() == SKILLMODE_CAST ) { _processDefCast( dwTime ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { if( GetStep() == STEP_00 ) { if( m_nFireMotionID != 0 ) { m_pOwner->NPlayAnimation( m_nFireMotionID, SEQTYPE_NORMAL, m_fPlayRate * 4.8f ); _addFX( m_pSkillFX->nStage_Type_Id ); _getEventSet(); SetStep( STEP_01 ); } else SetStep( STEP_02 ); } else if( GetStep() == STEP_01 ) { if( !m_pOwner->IsPlaying() ) { SetStep( STEP_02 ); } else if( m_pOwner->GetCurrAnimationID() != m_nFireMotionID ) { if( m_nHitCnt > 0 ) { m_pOwner->SetAniLock( false ); m_pOwner->NPlayAnimation( m_nFireMotionID, SEQTYPE_NORMAL, m_fPlayRate * 4.8f ); m_pOwner->SetAniLock( true ); _getEventSet(); } else { SetStep( STEP_02 ); return; } } } else if( GetStep() == STEP_02 ) { m_pOwner->EndUseSkill( m_pSkillFX->nID ); m_pOwner->Default(); SetEnd(TRUE); return; } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate ); _processEventSet( eventTime ); } void SWorkWeaponSwing_ContinuousHits::OnEventHit() { _processDamage(); } void SWorkWeaponSwing_ContinuousHits::OnEventSwing() { } void SWorkWeaponSwing_ContinuousHits::OnEventEtc() { } void SWorkWeaponSwing_ContinuousHits::_processDamage() { //타겟 만큼 순차적으로 데미지 처리 for( unsigned char target_count = 0; target_count < m_pSkillEvent->fire.target_count; ++target_count ) { if( m_nHitCnt > 0 ) { m_pDamage->skillresult = m_pSkillEvent->vSkillResult[m_nCount - m_nHitCnt]; SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_pDamage->skillresult.GetTargetHandle() ); if( pTarget ) { int nBlock = 0; int nCritical = 0; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_CRITICAL) nCritical = 1; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_BLOCK) nBlock = 1; m_pOwner->OnDamage( m_pOwner->GetArID(), pTarget->GetArID(), m_pDamage ); if( (m_pDamage->skillresult.GetType() == SkillResult::DAMAGE || m_pDamage->skillresult.GetType() == SkillResult::MAGIC_DAMAGE) && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { pTarget->Damage(); // Fraun performance tweak (TODO: return it back; testing purposes!) //std::string strScript; //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), pTarget->GetArID(), nCritical, nBlock ); //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); if( m_pSkillFX->nSub_Fire_Fx_Set_Id != 0 ) _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nSub_Fire_Fx_Set_Id, m_pSkillFX->nSub_Fire_Fx_Position ); if( m_pSkillFX->nHit_Fx_Set_Id != 0 ) _addEffect( pTarget->GetArID(), pTarget->GetArID(), pTarget->GetArID(), m_pSkillFX->nHit_Fx_Set_Id, m_pSkillFX->nHit_Fx_Set_Position_Id ); } } --m_nHitCnt; } } } //============================================================================================== //스킬 연출 유형 123 SWorkWeaponSwing_Zeal::SWorkWeaponSwing_Zeal( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { // m_nLocalFireMotionID[0] = pSkillFX->fStage_Data[2];//시전(타격)모션1 ID // m_nLocalFireMotionID[1] = pSkillFX->fStage_Data[3];//시전(타격)모션2 ID // m_nLocalFireMotionID[2] = pSkillFX->fStage_Data[4];//시전(타격)모션3 ID m_fPlayRate = pSkillFX->fStage_Data[1];//재생 배속 m_nCurMotionID = -1; m_cMaxHitCount = (int)pSkillFX->fStage_Data[9]; if( m_cMaxHitCount <= 0 ) { m_cMaxHitCount = 3; } m_pLocalFireMotionID = new int[m_cMaxHitCount]; for( unsigned char cMaxHitCount = 0; cMaxHitCount < m_cMaxHitCount; ++cMaxHitCount ) m_pLocalFireMotionID[cMaxHitCount] = pSkillFX->fStage_Data[2+cMaxHitCount]; //시전(타격)모션 } SWorkWeaponSwing_Zeal::~SWorkWeaponSwing_Zeal() { if( m_pOwner ) { m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( m_pTarget ) { while(m_nHitCnt > 0) _processDamage(); } } SAFE_DELETE_ARRAY( m_pLocalFireMotionID ); } void SWorkWeaponSwing_Zeal::OnEventHit() { _processDamage(); } bool SWorkWeaponSwing_Zeal::ProcessingDamage() { if( m_nHitCnt > 0 || GetSkillMode() != SKILLMODE_FIRE ) return false; return true; } void SWorkWeaponSwing_Zeal::_processDamage() { for( unsigned char target_count = 0; target_count < m_pSkillEvent->fire.target_count; ++target_count ) { if( m_nHitCnt > 0 ) { m_pDamage->skillresult = m_pSkillEvent->vSkillResult[m_nCount - m_nHitCnt]; SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_pDamage->skillresult.GetTargetHandle() ); if( pTarget ) { int nBlock = 0; int nCritical = 0; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_CRITICAL) nCritical = 1; if(m_pDamage->skillresult.damage.flag & TS_ATTACK_EVENT::FLAG_BLOCK) nBlock = 1; m_pOwner->OnDamage( m_pOwner->GetArID(), pTarget->GetArID(), m_pDamage ); if( (m_pDamage->skillresult.GetType() == SkillResult::DAMAGE || m_pDamage->skillresult.GetType() == SkillResult::MAGIC_DAMAGE) && !(m_pDamage->skillresult.damage.flag & SkillResult::MISS) ) { pTarget->Damage(); // Fraun performance tweak (TODO: return it back; testing purposes!) //std::string strScript; //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), pTarget->GetArID(), nCritical, nBlock ); //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); if( m_pSkillFX->nSub_Fire_Fx_Set_Id != 0 ) _addEffect( m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nSub_Fire_Fx_Set_Id, m_pSkillFX->nSub_Fire_Fx_Position ); if( m_pSkillFX->nHit_Fx_Set_Id != 0 ) _addEffect( pTarget->GetArID(), pTarget->GetArID(), pTarget->GetArID(), m_pSkillFX->nHit_Fx_Set_Id, m_pSkillFX->nHit_Fx_Set_Position_Id ); } } --m_nHitCnt; } } } void SWorkWeaponSwing_Zeal::Process( DWORD dwTime ) { if( IsEnd() ) return; m_dwTime = dwTime; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } _processView(); if( GetSkillMode() == SKILLMODE_CAST ) { _processDefCast( dwTime ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { if( GetStep() == STEP_00 ) { //1이면 랜덤 0이면 순차 if( m_pSkillFX->fStage_Data[0] > 0.0f) m_nCurMotionID = rand() % m_cMaxHitCount; else { ++m_nCurMotionID; if( m_nCurMotionID >= m_cMaxHitCount ) m_nCurMotionID = 0; } m_pOwner->SetAniLock( false ); m_pOwner->NPlayAnimation( m_pLocalFireMotionID[m_nCurMotionID], SEQTYPE_NORMAL, m_fPlayRate * 4.8f ); m_pOwner->SetAniLock( true ); _addFX( m_pSkillFX->nStage_Type_Id ); _getEventSet(); SetStep( STEP_01 ); } else if( GetStep() == STEP_01 ) { if( !m_pOwner->IsPlaying() ) { if( m_nHitCnt > 0 ) { //1이면 랜덤 0이면 순차 if( m_pSkillFX->fStage_Data[0] > 0.0f ) m_nCurMotionID = rand() % m_cMaxHitCount; else { ++m_nCurMotionID; if( m_nCurMotionID >= m_cMaxHitCount ) m_nCurMotionID = 0; } m_pOwner->SetAniLock( false ); m_pOwner->NPlayAnimation( m_pLocalFireMotionID[m_nCurMotionID], SEQTYPE_NORMAL, m_fPlayRate * 4.8f ); m_pOwner->SetAniLock( true ); _getEventSet(); } else { SetStep( STEP_02 ); return; } } else if( !CurrentlyAnimationIsFire() ) //연타 관련 모션을 재생중이지 않다면 끝낸다 { if( m_nHitCnt > 0 ) { m_pOwner->SetAniLock( false ); m_pOwner->NPlayAnimation( m_pLocalFireMotionID[m_nCurMotionID], SEQTYPE_NORMAL, m_fPlayRate * 4.8f ); m_pOwner->SetAniLock( true ); _getEventSet(); } else { SetStep( STEP_02 ); return; } } } else if( GetStep() == STEP_02 ) { m_pOwner->SetAniLock( false ); m_pOwner->EndUseSkill( m_pSkillFX->nID ); m_pOwner->Default(); SetEnd(TRUE); return; } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate ); _processEventSet( eventTime ); } bool SWorkWeaponSwing_Zeal::CurrentlyAnimationIsFire() { int nCurrentAniID = m_pOwner->GetCurrAnimationID(); for( unsigned char cMaxHitCount = 0; cMaxHitCount < m_cMaxHitCount; ++cMaxHitCount ) { if( nCurrentAniID == m_pLocalFireMotionID[cMaxHitCount] ) return true; } return false; } //============================================================================================== SWorkWeaponSwing_Leech::SWorkWeaponSwing_Leech( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//흡수체생성딜레이(초) pSkillFX->fStage_Data[1];//흡수체FX ID pSkillFX->fStage_Data[2];//흡수체FX 비행스타일 (0~2) pSkillFX->fStage_Data[3];//추가발동(회복) FX ID pSkillFX->fStage_Data[4];//추가발동(회복) FX 위치 } SWorkWeaponSwing_Leech::~SWorkWeaponSwing_Leech() { } void SWorkWeaponSwing_Leech::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } void SWorkWeaponSwing_Leech::OnEventHit() { _processDamage(); } void SWorkWeaponSwing_Leech::OnEventSwing() { } void SWorkWeaponSwing_Leech::OnEventEtc() { } //============================================================================================== SWorkBowShoot::SWorkBowShoot( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//연타연출타입 (0,1) pSkillFX->fStage_Data[1];//범위연출타입 (0,1) pSkillFX->fStage_Data[2];//슈팅형 발사체FX ID pSkillFX->fStage_Data[3];//슈팅형 발사체FX 비행속도 (-1,1~9) pSkillFX->fStage_Data[4];//연사간격(초) m_nEffectID[0] = -1; m_nEffectID[1] = -1; m_nEffectID[2] = -1; struct _MOTION_FX_SET* m_pFxSet = NULL; if( pSkillFX->nStage_Type_Id == SS_TYPE_201 ) { m_pFxSet = GetMotionFxSetDB().GetFXSet( pSkillFX->fStage_Data[5] ); } else if( pSkillFX->nStage_Type_Id == SS_TYPE_212 ) { m_pFxSet = GetMotionFxSetDB().GetFXSet( pSkillFX->fStage_Data[6] ); } // From ZONE source; dual crossbows bool bIsCrossBow = false; <<<<<<< HEAD if (ItemBase::CLASS_CROSSBOW == pOwner->GetItemClass()) //Double Crossbow ======= if (ItemBase::CLASS_CROSSBOW == pOwner->GetItemClass()) >>>>>>> a34328224e914a577b99c79ec6e8ffbcea554a05 bIsCrossBow = true; // AziaMafia Double Crossbow //if (ItemBase::CLASS_CROSSBOW == pOwner->GetItemClass()) // (ItemBase::CLASS_CROSSBOW || ItemBase::CLASS_DOUBLE_CROSSBOW == pOwner->GetItemClass()) // bIsCrossBow = true; if( m_pFxSet ) { m_strFX_01 = GetResourceDB().GetEffectResourceName( m_pFxSet->graphic_effect_start_file_ID ); m_strFX_02 = GetResourceDB().GetEffectResourceName( m_pFxSet->graphic_effect_middle_file_ID ); m_strFX_03 = GetResourceDB().GetEffectResourceName( m_pFxSet->graphic_effect_end_file_ID ); if( bIsCrossBow ) { <<<<<<< HEAD //Double Crossbow m_strFX_01 += "cba_"; m_strFX_02 += "cba_"; m_strFX_03 += "cba_"; ======= // AziaMafia Double Crossbow //m_strFX_01 += "cba_"; //m_strFX_02 += "cba_"; //m_strFX_03 += "cba_"; m_strFX_01 += "cbt_"; m_strFX_02 += "cbt_"; m_strFX_03 += "cbt_"; >>>>>>> a34328224e914a577b99c79ec6e8ffbcea554a05 } else { m_strFX_01 += "bwa_"; m_strFX_02 += "bwa_"; m_strFX_03 += "bwa_"; } } else { if( bIsCrossBow ) { m_strFX_01 = "rcfx_cross_arrowattack_start_lv01_"; m_strFX_02 = "rcfx_cross_arrowattack_loop_lv01_"; m_strFX_03 = "rcfx_cross_arrowattack_end_lv01_"; } else { m_strFX_01 = "rcfx_arrowattack_start_lv01_"; m_strFX_02 = "rcfx_arrowattack_loop_lv01_"; m_strFX_03 = "rcfx_arrowattack_end_lv01_"; /*m_strFX_01 = "rcfx_pillaroffirearrow_start_lv01_bwa_"; //Alucard Need test this if this from higher epic m_strFX_02 = "rcfx_pillaroffirearrow_loop_lv01_bwa_"; m_strFX_03 = "rcfx_pillaroffirearrow_end_lv01_bwa_";*/ } } const char* szName = GetNX3Name( pOwner->GetRace(), pOwner->GetSex() ); m_strFX_01 += szName; m_strFX_02 += szName; m_strFX_03 += szName; } SWorkBowShoot::~SWorkBowShoot() { if( m_pOwner ) { if( m_nEffectID[0] != -1 ) m_pOwner->DelEffect( m_nEffectID[0] ); if( m_nEffectID[1] != -1 ) m_pOwner->DelEffect( m_nEffectID[1] ); // if( m_nEffectID[2] != -1 ) m_pOwner->DelEffect( m_nEffectID[2] ); } } bool SWorkBowShoot::ProcessingDamage() { if( GetSkillMode() != SKILLMODE_FIRE || GetStep() != STEP_01 ) return false; return true; } void SWorkBowShoot::Process( DWORD dwTime ) { if( IsEnd() ) return; m_dwTime = dwTime; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } _processView(); if( GetSkillMode() == SKILLMODE_CAST ) { _processDefCast( dwTime ); //우선 애니메이션 체크로 화살 이펙트를 출력하자 if( m_pOwner->GetCurrAnimationID() == ANI_BOW_ATTACK01_A && m_nEffectID[0] == -1) m_nEffectID[0] = m_pOwner->AddEffect( &FX_DATA_EX( m_strFX_01.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true, SEQTYPE_NORMAL, m_fPlayRate*4.8f ) ); else if( m_pOwner->GetCurrAnimationID() == ANI_BOW_ATTACK01_B && m_nEffectID[1] == -1) m_nEffectID[1] = m_pOwner->AddEffect( &FX_DATA_EX( m_strFX_02.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true, SEQTYPE_LOOP, m_fPlayRate*4.8f ) ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { if( GetStep() == STEP_00 ) { //m_pOwner->AddAction( m_pSkillEvent ); if( m_nEffectID[2] == -1 ) m_nEffectID[2] = m_pOwner->AddEffect( &FX_DATA_EX( m_strFX_03.c_str(), 2, m_pOwner->GetArID(), m_pOwner->GetArID(), m_hTarget, EFFECT_POS_DAMAGE, true, SEQTYPE_NORMAL, m_fPlayRate*4.8f ) ); } _processDefFire( dwTime ); } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } //============================================================================================== SWorkBowShoot_Shove::SWorkBowShoot_Shove( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//연타연출타입 (0,1) pSkillFX->fStage_Data[1];//범위연출타입 (0,1) pSkillFX->fStage_Data[2];//슈팅형 발사체FX ID pSkillFX->fStage_Data[3];//슈팅형 발사체FX 비행속도 (-1,1~9) pSkillFX->fStage_Data[4];//연사간격(초) pSkillFX->fStage_Data[5];//밀려나는속도 (1~9) SetEnd( true ); } SWorkBowShoot_Shove::~SWorkBowShoot_Shove() { } //============================================================================================== SWorkBowShoot_Leech::SWorkBowShoot_Leech( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//연타연출타입 (0,1) pSkillFX->fStage_Data[1];//범위연출타입 (0,1) pSkillFX->fStage_Data[2];//슈팅형 발사체FX ID pSkillFX->fStage_Data[3];//슈팅형 발사체FX 비행속도 (-1,1~9) pSkillFX->fStage_Data[4];//연사간격(초) pSkillFX->fStage_Data[5];//흡수체생성딜레이(초) pSkillFX->fStage_Data[6];//흡수체FX 파일명 pSkillFX->fStage_Data[7];//흡수체FX 비행스타일 (0~2) pSkillFX->fStage_Data[8];//추가발동(회복) FX ID pSkillFX->fStage_Data[9];//추가발동(회복) FX 위치 SetEnd( true ); } SWorkBowShoot_Leech::~SWorkBowShoot_Leech() { } //============================================================================================== SWorkSelf::SWorkSelf( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { } SWorkSelf::~SWorkSelf() { } void SWorkSelf::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); } //============================================================================================== SWorkMotion::SWorkMotion( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { } SWorkMotion::~SWorkMotion() { } bool SWorkMotion::ProcessingDamage() { if( GetSkillMode() != SKILLMODE_FIRE || GetStep() != STEP_01 ) return false; return true; } void SWorkMotion::Process( DWORD dwTime ) { if( IsEnd() ) return; m_dwTime = dwTime; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } _processView(); if( GetSkillMode() == SKILLMODE_CAST ) { _processDefCast( dwTime ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { if( GetStep() == STEP_00 ) { if( m_pSkillEvent ) m_pOwner->AddAction( m_pSkillEvent ); } _processDefFire( dwTime ); } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } //============================================================================================== SWorkMotion_Leech::SWorkMotion_Leech( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//흡수체생성딜레이(초) pSkillFX->fStage_Data[1];//흡수체FX ID pSkillFX->fStage_Data[2];//흡수체FX 비행스타일 (0~2) pSkillFX->fStage_Data[3];//추가발동(회복) FX ID pSkillFX->fStage_Data[4];//추가발동(회복) FX 위치 } SWorkMotion_Leech::~SWorkMotion_Leech() { } bool SWorkMotion_Leech::ProcessingDamage() { if( GetSkillMode() != SKILLMODE_FIRE || GetStep() != STEP_01 ) return false; return true; } void SWorkMotion_Leech::Process( DWORD dwTime ) { if( IsEnd() ) return; m_dwTime = dwTime; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd(true); return; } _processView(); if( GetSkillMode() == SKILLMODE_CAST ) { _processDefCast( dwTime ); } else if( GetSkillMode() == SKILLMODE_FIRE ) { _processDefFire( dwTime ); if( GetStep() == STEP_00 ) { m_pOwner->AddAction( m_pSkillEvent ); } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } //============================================================================================== SWorkMotion_SummonMotion_Leech::SWorkMotion_SummonMotion_Leech( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//흡수체생성딜레이(초) pSkillFX->fStage_Data[1];//흡수체FX ID pSkillFX->fStage_Data[2];//흡수체FX 비행스타일 (0~2) pSkillFX->fStage_Data[3];//추가발동(회복) FX ID pSkillFX->fStage_Data[4];//추가발동(회복) FX 위치 } SWorkMotion_SummonMotion_Leech::~SWorkMotion_SummonMotion_Leech() { } void SWorkMotion_SummonMotion_Leech::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkMotion_FXMotion::SWorkMotion_FXMotion( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//발동형 발사체FX ID pSkillFX->fStage_Data[1];//발동형 발사체FX 위치 pSkillFX->fStage_Data[2];//발동형 발사체 FX 방향 랜덤처리 (0:한방향 1:랜덤방향) pSkillFX->fStage_Data[3];//연사간격(초) pSkillFX->fStage_Data[4];//힛트타이밍(초) } SWorkMotion_FXMotion::~SWorkMotion_FXMotion() { } void SWorkMotion_FXMotion::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkMotion_FXMotionMultiple::SWorkMotion_FXMotionMultiple( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//발동형 발사체FX ID pSkillFX->fStage_Data[1];//발동형 발사체FX 위치 pSkillFX->fStage_Data[2];//발동형 발사체 FX 방향 랜덤처리 (0:한방향 1:랜덤방향) pSkillFX->fStage_Data[3];//연사간격(초) pSkillFX->fStage_Data[4];//힛트타이밍(초) } SWorkMotion_FXMotionMultiple::~SWorkMotion_FXMotionMultiple() { } void SWorkMotion_FXMotionMultiple::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkShoot_FXShoot::SWorkShoot_FXShoot( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//슈팅형 발사체FX ID pSkillFX->fStage_Data[1];//슈팅형 발사체 비행 타입 (0~) pSkillFX->fStage_Data[2];//슈팅형 발사체 비행속도 (1~9) pSkillFX->fStage_Data[3];//슈팅형 발사체 비행 가속 (0~9) pSkillFX->fStage_Data[4];//연사간격(초) } SWorkShoot_FXShoot::~SWorkShoot_FXShoot() { } void SWorkShoot_FXShoot::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkShoot_FXShootMultiple::SWorkShoot_FXShootMultiple( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//슈팅형 발사체FX ID pSkillFX->fStage_Data[1];//슈팅형 발사체 비행 타입 (0~) pSkillFX->fStage_Data[2];//슈팅형 발사체 비행속도 (1~9) pSkillFX->fStage_Data[3];//슈팅형 발사체 비행 가속 (0~9) pSkillFX->fStage_Data[4];//연사간격(초) } SWorkShoot_FXShootMultiple::~SWorkShoot_FXShootMultiple() { } void SWorkShoot_FXShootMultiple::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkShoot_FXShootPenetrate::SWorkShoot_FXShootPenetrate( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//슈팅형 발사체FX ID pSkillFX->fStage_Data[1];//슈팅형 발사체 비행 타입 (0~) pSkillFX->fStage_Data[2];//슈팅형 발사체 비행속도 (1~9) pSkillFX->fStage_Data[3];//슈팅형 발사체 비행 가속 (0~9) pSkillFX->fStage_Data[4];//연사간격(초) } SWorkShoot_FXShootPenetrate::~SWorkShoot_FXShootPenetrate() { } void SWorkShoot_FXShootPenetrate::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } /// 2011.03.23 - prodongi //============================================================================================== SWorkShoot_FXShootChain::SWorkShoot_FXShootChain( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//슈팅형 발사체FX ID pSkillFX->fStage_Data[1];//슈팅형 발사체 비행 타입 (0~) pSkillFX->fStage_Data[2];//슈팅형 발사체 비행속도 (1~9) pSkillFX->fStage_Data[3];//슈팅형 발사체 비행 가속 (0~9) pSkillFX->fStage_Data[4];//연사간격(초) } SWorkShoot_FXShootChain::~SWorkShoot_FXShootChain() { } void SWorkShoot_FXShootChain::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== SWorkGround_FXContinue::SWorkGround_FXContinue( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) { pSkillFX->fStage_Data[0];//지속발동체FX ID } SWorkGround_FXContinue::~SWorkGround_FXContinue() { } void SWorkGround_FXContinue::Process( DWORD dwTime ) { if( IsEnd() ) return; SNewSkill::Process( dwTime ); _processView(); } //============================================================================================== //============================================================================================== SWorkKnockBack::SWorkKnockBack( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX, const SkillResult* pSkillResult ) : SNewSkill( pOwner, pSkillFX ) { m_pDamage = NULL; m_hTarget = pSkillResult->damage_kb.hTarget; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd( TRUE ); return; } //타겟이 이동중일경우 정지명령을 내린다 m_pTarget->SetArObjectStop(); m_nFireMotionID = pSkillFX->fStage_Data[6]; m_nFxSubHitID = pSkillFX->nHit_Fx_Set_Id; m_nFxSubFireID = pSkillFX->nSub_Fire_Fx_Set_Id; m_dwAddHitDelayTime = pSkillFX->nSub_Hit_Fx_OutPut_Delay * 1000; m_dwAddFireDelayTime = pSkillFX->nFire_Fx_OutPut_Delay * 1000; m_nFxSubHitPos = pSkillFX->nHit_Fx_Set_Position_Id; m_nFxSubFirePos = pSkillFX->nSub_Fire_Fx_Position; m_vKnockBackPosition = K3DVector( pSkillResult->damage_kb.x, pSkillResult->damage_kb.y, 0.0f ); m_fKnockBackSpeed = pSkillResult->damage_kb.speed; m_pDamage = new SMSG_DAMAGE; m_pDamage->attacker_handle = pOwner->GetArID(); m_pDamage->target_handle = m_hTarget; m_pDamage->nDamage = pSkillResult->damage_kb.damage; m_pDamage->flag = pSkillResult->damage_kb.flag; m_pDamage->nHittingAdd_FxID = pSkillFX->nSub_Stage_On_Hit_Id; m_pDamage->skillresult = *pSkillResult; m_pDamage->nSkillID = pSkillFX->nID; /// 2011.05.16 - prodongi SetDamageDisplayName( m_pDamage, m_pTarget ); SetStep( STEP_00 ); } SWorkKnockBack::~SWorkKnockBack() { SAFE_DELETE( m_pDamage ); } bool SWorkKnockBack::ProcessingDamage() { if( GetStep() != STEP_02 ) return false; return true; } void SWorkKnockBack::Process( DWORD dwTime ) { if( IsEnd() ) return; // Fraun performance tweak m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd( TRUE ); return; } int nStep = GetStep(); switch (nStep) { case STEP_00: { if (m_nFireMotionID != 0) { m_pOwner->NPlayAnimation(m_nFireMotionID); _getEventSet(); } if (m_pDamage) { m_pTarget->OnDamage(m_pOwner->GetArID(), m_hTarget, m_pDamage); if (!(m_pDamage->flag & TS_ATTACK_EVENT::FLAG_MISS) && m_pDamage->nDamage > 0) { _addFX(m_pSkillFX->nStage_Type_Id); if (m_pTarget->GetHP() > 0) { m_pTarget->SetAniLock(false); m_pTarget->NPlayAnimation(ANI_DAMAGE01, SEQTYPE_LOOP); } m_pTarget->Damage(); // Removed FX in case of performance //std::string strScript; //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), m_pTarget->GetArID(), // ( m_pDamage->flag & TS_ATTACK_EVENT::FLAG_CRITICAL ), // ( m_pDamage->flag & TS_ATTACK_EVENT::FLAG_BLOCK ) ); //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); } } SetStep(STEP_01); break; } case STEP_01: { m_pTarget->SetKnockBack(m_vKnockBackPosition, m_fKnockBackSpeed); SetStep(STEP_02); break; } case STEP_02: { if (!m_pOwner->IsPlaying() || m_pOwner->GetCurrAnimationID() != m_nFireMotionID) { m_pOwner->Default(); SetEnd(TRUE); return; } break; } } if( m_nFxSubHitID > 0 ) { if( ( dwTime - m_dwStartTime ) > m_dwAddHitDelayTime ) { _addEffect( m_pTarget->GetArID(), m_nFxSubHitID, m_nFxSubHitPos ); m_nFxSubHitID = -1; } } if( m_nFxSubFireID > 0 ) { if( ( dwTime - m_dwStartTime ) > m_dwAddFireDelayTime ) { _addEffect( m_pTarget->GetArID(), m_nFxSubFireID, m_nFxSubFirePos ); m_nFxSubFireID = -1; } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } //============================================================================================== SWorkRush_Shove::SWorkRush_Shove( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX, const struct SStateInfo * pStateInfo ) : SGameWork( pOwner ) { m_nFireMotionID = pSkillFX->fStage_Data[0]; //돌진모션 ID m_fPlayRate = pSkillFX->fStage_Data[1] * 4.8f;//모션속도변화 (1=100%, 클수록 빨라짐) m_pOwner->SetViewVector( pStateInfo->vTargetPos ); m_pOwner->SetAniLock( false ); m_pOwner->Rush( m_nFireMotionID, m_fPlayRate ); if( pSkillFX->fStage_Data[2] != 0 ) { FX_DATA fx_data; fx_data.owner = m_pOwner->GetArID(); fx_data.attack = m_pOwner->GetArID(); fx_data.target = m_pOwner->GetArID(); fx_data.nFX_ID = pSkillFX->fStage_Data[2]; fx_data.nEffPos = pSkillFX->fStage_Data[3]; m_pOwner->AddEffect( &fx_data ); } m_pSkillFX = pSkillFX; SetEnd( TRUE ); } SWorkRush_Shove::~SWorkRush_Shove() { SAFE_DELETE( m_pSkillFX ); } void SWorkRush_Shove::Process( DWORD dwTime ) { if( IsEnd() ) return; } //============================================================================================== //돌진공격 SChargeAttack::SChargeAttack( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX, const SkillResult* pSkillResult ) : SNewSkill( pOwner, pSkillFX ) { m_pDamage = NULL; m_hTarget = pSkillResult->damage.hTarget; m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd( TRUE ); return; } m_nFireMotionID = pSkillFX->fStage_Data[6]; m_nFxSubHitID = pSkillFX->nHit_Fx_Set_Id; m_nFxSubFireID = pSkillFX->nSub_Fire_Fx_Set_Id; m_dwAddHitDelayTime = pSkillFX->nSub_Hit_Fx_OutPut_Delay * 1000; m_dwAddFireDelayTime = pSkillFX->nFire_Fx_OutPut_Delay * 1000; m_nFxSubHitPos = pSkillFX->nHit_Fx_Set_Position_Id; m_nFxSubFirePos = pSkillFX->nSub_Fire_Fx_Position; m_pDamage = new SMSG_DAMAGE; m_pDamage->attacker_handle = pOwner->GetArID(); m_pDamage->target_handle = m_hTarget; m_pDamage->nDamage = pSkillResult->damage.damage; m_pDamage->flag = pSkillResult->damage.flag; m_pDamage->nHittingAdd_FxID = pSkillFX->nSub_Stage_On_Hit_Id; m_pDamage->skillresult = *pSkillResult; SetDamageDisplayName( m_pDamage, m_pTarget ); SetStep( STEP_00 ); } SChargeAttack::~SChargeAttack() { SAFE_DELETE( m_pDamage ); } void SChargeAttack::Process( DWORD dwTime ) { if( IsEnd() ) return; // Fraun performance tweak m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { SetEnd( TRUE ); return; } int nStep = GetStep(); switch (nStep) { case STEP_00: { if (m_nFireMotionID != 0) { m_pOwner->NPlayAnimation(m_nFireMotionID); _getEventSet(); } if (m_pDamage) { m_pTarget->OnDamage(m_pOwner->GetArID(), m_hTarget, m_pDamage); if (!(m_pDamage->flag & TS_ATTACK_EVENT::FLAG_MISS) && m_pDamage->nDamage > 0) { _addFX(m_pSkillFX->nStage_Type_Id); if (m_pTarget->GetHP() > 0) { m_pTarget->SetAniLock(false); m_pTarget->NPlayAnimation(ANI_DAMAGE01, SEQTYPE_LOOP); } m_pTarget->Damage(); // Removed FX in case of performance //std::string strScript; //XStringUtil::Format( strScript, "%s( %u, %u, %d, %d )", "avatar_basic_hit", m_pOwner->GetArID(), m_pTarget->GetArID(), // (m_pDamage->flag & TS_ATTACK_EVENT::FLAG_CRITICAL), // (m_pDamage->flag & TS_ATTACK_EVENT::FLAG_BLOCK) ); //if( strScript.length() ) // LUA()->RunString( strScript.c_str() ); } } SetStep(STEP_01); break; } case STEP_01: { if (!m_pOwner->IsPlaying() || m_pOwner->GetCurrAnimationID() != m_nFireMotionID) { m_pOwner->Default(); SetEnd(TRUE); return; } break; } } if( m_nFxSubHitID > 0 ) { if( ( dwTime - m_dwStartTime ) > m_dwAddHitDelayTime ) { _addEffect( m_pTarget->GetArID(), m_nFxSubHitID, m_nFxSubHitPos ); m_nFxSubHitID = -1; } } if( m_nFxSubFireID > 0 ) { if( ( dwTime - m_dwStartTime ) > m_dwAddFireDelayTime ) { _addEffect( m_pTarget->GetArID(), m_nFxSubFireID, m_nFxSubFirePos ); m_nFxSubFireID = -1; } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); } bool SChargeAttack::ProcessingDamage() { if( GetStep() != STEP_01 ) return false; return true; } //============================================================================================== //타기 SWorkMount::SWorkMount( class SGameAvatarEx * pOwner, AR_HANDLE hTarger ) : SGameWork( pOwner ) , m_pCreature( NULL ) { m_hCreatrue = hTarger; m_dwOldTime = 0; /// 2011.09.06 바로 탑승하도록 수정 - prodongi //SetStep( STEP_00 ); SetStep( STEP_01 ); } SWorkMount::~SWorkMount() { if( m_pOwner ) { m_pCreature = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hCreatrue ); if( m_pCreature ) { m_pOwner->SetRiderCreatureInfo( &SGameAvatarEx::RiderCreatureInfo( m_hCreatrue, EFFECT_POS_SADDLE, m_pCreature->GetCreatureMountType() ) ); m_pOwner->SetMountMode(); m_pCreature->SetMountMode(); } else { m_pOwner->SetRiderCreatureInfo( &SGameAvatarEx::RiderCreatureInfo( m_hCreatrue, EFFECT_POS_SADDLE ) ); } } } void SWorkMount::Process( DWORD dwTime ) { if( IsEnd() ) return; // Fraun performance tweak if( m_dwOldTime == 0 ) m_dwOldTime = dwTime; m_pCreature = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hCreatrue ); int nStep = GetStep(); switch (nStep) { case STEP_00: { // If movement occurs with the mount motion in Step 0, immediately switch to Step 1 (this can happen to other players) if (m_pOwner->IsMoving() && (m_pOwner->CurrentlyAnimationIsMWalk() || m_pOwner->CurrentlyAnimationIsMRun())) // sonador #2.1.6 { SetStep(STEP_01); return; } // If movement to the position sent by the server has finished… if (!m_pOwner->IsMoving()) { m_pOwner->SetMotionBlend(false); m_pOwner->SetIng(true); if (m_pCreature) { int nAniType; switch (m_pCreature->GetCreatureMountType()) { case SGameAvatarEx::RIDE_HIGH_TYPE: nAniType = ANI_M_MOUNT_HIGH; break; case SGameAvatarEx::RIDE_LOW_TYPE: nAniType = ANI_M_MOUNT_LOW; break; case SGameAvatarEx::RIDE_WHITE_TYPE: nAniType = ANI_M_MOUNT01_WHITE; break; case SGameAvatarEx::RIDE_UNICORN_TYPE: nAniType = ANI_M_MOUNT01_UNICORN; break; default: nAniType = ANI_M_MOUNT_HIGH; break; } m_pOwner->SetAniLock(false); m_pOwner->NPlayAnimation(nAniType); m_pOwner->SetAniLock(true); // Rotate the creature to face the player m_pCreature->SetViewVectorForMount(m_pOwner->GetViewVector()); m_pCreature->SetIng(true); m_pCreature->SetAniLock(false); m_pCreature->NPlayAnimation(nAniType); m_pCreature->SetAniLock(true); } SetStep(STEP_01); } break; } case STEP_01: { // Has the mounting animation finished? // If movement occurs before the mounting animation finishes, link immediately // (this can happen for other players as well) // If the mounting animation differs from the currently playing animation, link immediately if (!m_pOwner->IsPlaying() || m_pOwner->IsMoving() || !m_pOwner->CurrentlyAnimationIsMount()) { m_pOwner->SetIng(false); m_pOwner->SetAniLock(false); if (m_pCreature) { m_pOwner->SetRiderCreatureInfo(&SGameAvatarEx::RiderCreatureInfo(m_hCreatrue, EFFECT_POS_SADDLE, m_pCreature->GetCreatureMountType())); // 2011.09.06 Modified to mount immediately – prodongi m_pOwner->SetMotionBlend(false); if (m_pOwner->IsMoving()) m_pOwner->NPlayAnimation( m_pOwner->GetPlayerMRunAniID(), SEQTYPE_LOOP ); else m_pOwner->NPlayAnimation( m_pOwner->GetPlayerMDefAniID(), SEQTYPE_LOOP ); m_pCreature->SetIng(false); m_pCreature->SetAniLock(false); m_pCreature->StandingDegree(); m_pCreature->SetViewVectorForMount(m_pOwner->GetViewVector()); if (m_pCreature->IsMoving()) m_pCreature->NPlayAnimation( ANI_RUN, SEQTYPE_LOOP ); else m_pCreature->NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); // 2011.09.06 Play mount effect – prodongi // Normally, the effect ID should be obtained from the riding persistent effect, // but since mount-type creatures don’t have related persistent effects, it is hardcoded. FX_DATA fxdata; fxdata.nFX_ID = 18015; fxdata.nEffPos = EFFECT_POS_BOTTOM; fxdata.owner = m_pOwner->GetArID(); fxdata.attack = m_pOwner->GetArID(); fxdata.target = m_pOwner->GetArID(); fxdata.fPlayRate = 4.8f; fxdata.nPlayID = 0;//한번 fxdata.nMode = 0;//기본 m_pOwner->AddEffect(&fxdata); } SetStep(STEP_02); } break; } case STEP_02: { // 2011.09.06 Modified so that mounting happens immediately – prodongi SetEnd(TRUE); return; break; } } // If 10 seconds have passed and it’s still in Step 0, immediately link and finish it if( dwTime - m_dwOldTime > 10000 && nStep == STEP_00 ) { m_pOwner->SetIng( false ); m_pOwner->SetAniLock( false ); if( m_pCreature ) { m_pOwner->SetRiderCreatureInfo( &SGameAvatarEx::RiderCreatureInfo( m_hCreatrue, EFFECT_POS_SADDLE, m_pCreature->GetCreatureMountType() ) ); m_pCreature->SetIng( false ); m_pCreature->SetAniLock( false ); m_pCreature->StandingDegree(); if( m_pOwner->IsMoving() ) m_pOwner->NPlayAnimation( m_pOwner->GetPlayerMRunAniID(), SEQTYPE_LOOP ); else m_pOwner->NPlayAnimation( m_pOwner->GetPlayerMDefAniID(), SEQTYPE_LOOP ); if( m_pCreature->IsMoving() ) m_pCreature->NPlayAnimation( ANI_RUN, SEQTYPE_LOOP ); else m_pCreature->NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); } SetStep( STEP_02 ); } } //============================================================================================== // Dismount SWorkUnMount::SWorkUnMount( class SGameAvatarEx * pOwner, AR_HANDLE hTarger, char Flag ) : SGameWork( pOwner ) , m_pCreature( NULL ) { m_hCreatrue = hTarger; m_Flag = Flag; m_dwOldTime = 0; SetStep( STEP_01 ); } SWorkUnMount::~SWorkUnMount() { if( m_pOwner ) { m_pOwner->SetRiderCreatureInfo(); m_pOwner->SetDefaultView(); m_pOwner->SetNormalMode(); m_pCreature = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hCreatrue ); if( m_pCreature ) { m_pCreature->SetNormalMode(); } } } void SWorkUnMount::Process( DWORD dwTime ) { if( IsEnd() ) return; // Fraun performance tweak if( m_dwOldTime == 0 ) m_dwOldTime = dwTime; m_pCreature = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hCreatrue ); int nStep = GetStep(); switch (nStep) { case STEP_00: { // When the character falls off the creature or SP reaches 0 and the creature is summoned switch (m_Flag) { case TS_SC_UNMOUNT_SUMMON::FALL: case TS_SC_UNMOUNT_SUMMON::UNSUMMON: { m_pOwner->NPlayAnimation(ANI_DEFAULT01, SEQTYPE_LOOP); // t needs to be changed to a stun motion // Unlink m_pOwner->SetRiderCreatureInfo(); m_pOwner->SetIng(false); m_pOwner->SetMotionBlend(true); m_pOwner->SetAniLock(false); m_pOwner->UnMountFallUnSummon(); if (m_pCreature) { m_pCreature->SetIng(false); m_pCreature->SetAniLock(false); m_pCreature->Default(); m_pCreature->SetBestPosition(); // Moving the creature m_pCreature->UnMountFallUnSummon(); } SetEnd(TRUE); break; } case TS_SC_UNMOUNT_SUMMON::NORMAL: { if (!m_pOwner->IsMoving()) // The animation must play while in a standing state { m_pOwner->SetRiderCreatureInfo(); // Unlink m_pOwner->SetIng(true); // It is in the process of descending m_pOwner->SetMotionBlend(false); // Disable motion interpolation if (m_pCreature) { int nAniType; switch (m_pCreature->GetCreatureMountType()) { case SGameAvatarEx::RIDE_HIGH_TYPE: nAniType = ANI_M_UNMOUNT_HIGH; break; case SGameAvatarEx::RIDE_LOW_TYPE: nAniType = ANI_M_UNMOUNT_LOW; break; case SGameAvatarEx::RIDE_WHITE_TYPE: nAniType = ANI_M_UNMOUNT01_WHITE; break; case SGameAvatarEx::RIDE_UNICORN_TYPE: nAniType = ANI_M_UNMOUNT01_UNICORN; break; default: nAniType = ANI_M_UNMOUNT_HIGH; break; } m_pCreature->SetIng(true); m_pOwner->SetAniLock(false); m_pOwner->NPlayAnimation(nAniType); m_pOwner->SetAniLock(true); m_pCreature->SetAniLock(false); m_pCreature->NPlayAnimation(nAniType); m_pCreature->SetAniLock(true); } SetStep(STEP_01); } else { m_pOwner->SetRiderCreatureInfo(); m_pOwner->SetIng(false); m_pOwner->SetAniLock(false); m_pOwner->Default(); if (m_pCreature) { m_pCreature->SetIng(false); m_pCreature->SetAniLock(false); m_pCreature->SetBestPosition(); //Moving the creature m_pCreature->Default(); } SetEnd(TRUE); // If moving, immediately disconnect the link (it must not descend while moving). } break; } } break; } case STEP_01: { // If the descending motion has finished // If movement occurred even though the descending animation hasn’t finished, switch to the default animation // (other players might see the character standing up) // If the descending animation and the currently playing animation are different, switch to the default animation m_pOwner->SetIng(false); m_pOwner->SetMotionBlend(true); m_pOwner->SetAniLock(false); if (m_pOwner->IsMoving()) m_pOwner->Run(); else m_pOwner->Default(); if (m_pCreature) { m_pCreature->SetIng(false); m_pCreature->SetAniLock(false); if (m_pCreature->IsMoving()) m_pCreature->Run(); else m_pCreature->Default(); m_pCreature->SetBestPosition(); // Moving the creature /// 2011.09.06 탑승 이펙트 출력 - prodongi /// 원래는 이펙트 id를 라이딩 지속효과에서 갖고 와야 되나, 탑승형 크리처는 관련된 지속효과가 없기 때문에, 하드코딩으로 해줌 FX_DATA fxdata; fxdata.nFX_ID = 18015; fxdata.nEffPos = EFFECT_POS_BOTTOM; fxdata.owner = m_pOwner->GetArID(); fxdata.attack = m_pOwner->GetArID(); fxdata.target = m_pOwner->GetArID(); fxdata.fPlayRate = 4.8f; fxdata.nPlayID = 0; // Once fxdata.nMode = 0; // Default m_pOwner->AddEffect(&fxdata); } SetEnd(TRUE); } } // If 10 seconds have passed and it’s still stuck at step 0, immediately switch to step 1 if( dwTime - m_dwOldTime > 10000 && nStep == STEP_00 ) { m_pOwner->SetRiderCreatureInfo(); m_pOwner->SetIng( false ); m_pOwner->SetAniLock( false ); m_pOwner->Default(); if( m_pCreature ) { m_pCreature->SetIng( false ); m_pCreature->SetAniLock( false ); m_pCreature->SetBestPosition(); m_pCreature->Default(); } SetEnd( TRUE ); } } //============================================================================================== //애니 없이 타기 SWorkMountWithOutAnimation::SWorkMountWithOutAnimation( class SGameAvatarEx * pOwner, AR_HANDLE hTarger, int nFXID, int nFXPos ) : SGameWork( pOwner ) , m_hCreatrue( hTarger ) , m_nFXID( nFXID ) , m_nFXPos( nFXPos ) , m_pCreature( NULL ) { SetStep( STEP_00 ); } SWorkMountWithOutAnimation::~SWorkMountWithOutAnimation() { if( m_pOwner ) { m_pOwner->SetMotionBlend( true ); m_pCreature = (SGameAvatarEx*)m_pOwner->GetGameTransportCreatureObject( m_hCreatrue ); // sonador #2.1.6 크리쳐 기린(spirit_qilin) 테스트 if( m_pCreature ) { m_pOwner->SetRiderCreatureInfo( &SGameAvatarEx::RiderCreatureInfo( m_hCreatrue, EFFECT_POS_SADDLE, m_pCreature->GetCreatureMountType(), true ) ); m_pOwner->SetMountMode(); m_pCreature->SetVisibility( 1.0f ); m_pCreature->SetMountMode(); } else m_pOwner->SetRiderCreatureInfo( &SGameAvatarEx::RiderCreatureInfo( m_hCreatrue, EFFECT_POS_SADDLE, 2, true ) ); } } void SWorkMountWithOutAnimation::Process( DWORD dwTime ) { if( IsEnd() ) return; m_pCreature = (SGameAvatarEx*)m_pOwner->GetGameTransportCreatureObject( m_hCreatrue ); if( m_pCreature == NULL ) return; int nStep = GetStep(); if( nStep == STEP_00 ) { if( m_pCreature->IsInit() && m_pCreature->Activate() ) { // sonador #2.1.6 m_pOwner->SetRiderCreatureInfo( &SGameAvatarEx::RiderCreatureInfo( m_hCreatrue, EFFECT_POS_SADDLE, m_pCreature->GetCreatureMountType(), true ) ); int nRunAniType = m_pOwner->GetPlayerMRunAniID(); int nDefaultAniType = m_pOwner->GetPlayerMDefAniID(); m_pOwner->SetMotionBlend( false ); if( m_pOwner->IsMoving() ) m_pOwner->NPlayAnimation( nRunAniType, SEQTYPE_LOOP ); else m_pOwner->NPlayAnimation( nDefaultAniType, SEQTYPE_LOOP ); //크리처를 플레이어 방향으로 돌리자 m_pCreature->StandingDegree(); m_pCreature->SetViewVectorForMount( m_pOwner->GetViewVector() ); if( m_pOwner->IsMoving() ) m_pCreature->NPlayAnimation( ANI_RUN, SEQTYPE_LOOP ); else m_pCreature->NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); m_pCreature->SetViewVectorStateIdle( K3DVector( 0.0f, 0.0f, 0.0f ) ); m_pCreature->SetVisibility( 1.0f ); m_pOwner->SetMountMode(); m_pCreature->SetMountMode(); if( m_nFXID != 0 ) { FX_DATA fxdata; fxdata.nFX_ID = m_nFXID; fxdata.nEffPos = m_nFXPos; fxdata.owner = m_pOwner->GetArID(); fxdata.attack = m_pOwner->GetArID(); fxdata.target = m_pOwner->GetArID(); fxdata.fPlayRate = 4.8f; fxdata.nPlayID = 0;//한번 fxdata.nMode = 0;//기본 m_pOwner->AddEffect( &fxdata ); } SetEnd( TRUE ); } } } //============================================================================================== //애니 없이 내리기 SWorkUnMountWithOutAnimation::SWorkUnMountWithOutAnimation( class SGameAvatarEx * pOwner, AR_HANDLE hTarger, int nFXID, int nFXPos ) : SGameWork( pOwner ) , m_nFXID( nFXID ) , m_nFXPos( nFXPos ) , m_pCreature( NULL ) { m_pOwner->SetMotionBlend( false ); m_pOwner->SetNormalMode(); m_pOwner->SetRiderCreatureInfo(); m_pOwner->SetDefaultView(); if( m_pOwner->IsMoving() ) m_pOwner->Run(); else m_pOwner->Default(); FX_DATA fxdata; fxdata.nFX_ID = m_nFXID; fxdata.nEffPos = m_nFXPos; fxdata.owner = m_pOwner->GetArID(); fxdata.attack = m_pOwner->GetArID(); fxdata.target = m_pOwner->GetArID(); fxdata.fPlayRate = 4.8f; fxdata.nPlayID = 0;//한번 fxdata.nMode = 0;//기본 m_pOwner->AddEffect( &fxdata ); SetEnd( TRUE ); } SWorkUnMountWithOutAnimation::~SWorkUnMountWithOutAnimation() { if( m_pOwner ) { m_pOwner->SetMotionBlend( true ); m_pOwner->SetNormalMode(); } } void SWorkUnMountWithOutAnimation::Process( DWORD dwTime ) { /* if( IsEnd() == false ) { m_pOwner->SetMotionBlend( true ); m_pOwner->SetNormalMode(); SetEnd( TRUE ); }*/ } //============================================================================================== //광역 공격 SWorkMultiAttack::SWorkMultiAttack( class SGameAvatarEx * pOwner ) : SGameWork( pOwner ) , m_vStartDir( K3DVector( 0.0f, 0.0f, 0.0f ) ) , m_dwOldTime( 0 ) , m_dwRotationTime( 300 ) , m_fCheckAngle( 0.95f ) { m_fRangeAngle = K3D_PI*2.0f; //범위 각도 } SWorkMultiAttack::~SWorkMultiAttack() { if( m_pOwner ) { std::vector< TargetInfo >::iterator iter = m_vTargetInfo.begin(); for( ; iter != m_vTargetInfo.end(); ++iter ) { //처리가 안된넘들 체크 SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( (*iter).hTarget ); if( pTarget ) { //데미지 처리 pTarget->NPlayAnimation( ANI_DAMAGE01 ); } } } m_vTargetInfo.clear(); } void SWorkMultiAttack::SetTargetList( std::vector< AR_HANDLE > & vTargetList ) { std::vector< AR_HANDLE >::iterator iter = vTargetList.begin(); for( ; iter != vTargetList.end(); ++iter ) { TargetInfo target( (*iter) ); m_vTargetInfo.push_back( target ); } } void SWorkMultiAttack::Process( DWORD dwTime ) { if( m_dwOldTime == 0 ) m_dwOldTime = dwTime; int nStep = GetStep(); if( nStep == STEP_00 ) { K3DVector vView = m_pOwner->GetViewVector(); K3DVector vUp = K3DVector( 0.0f, 0.0f, 1.0f ); m_vStartDir = CrossProduct( vView, vUp ); //타겟 정리 std::vector< TargetInfo >::iterator iter = m_vTargetInfo.begin(); for( ; iter != m_vTargetInfo.end(); ++iter ) { SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( (*iter).hTarget ); if( pTarget ) { K3DVector vTarget; vTarget.x = pTarget->GetPosition()->x - m_pOwner->GetPosition()->x; vTarget.y = pTarget->GetPosition()->y - m_pOwner->GetPosition()->y; vTarget.z = 0.0f; K3DVectorNormalize( vTarget, vTarget ); K3DVector vCross = CrossProduct( m_vStartDir, vTarget ); if( vCross.z >= 0.0f ) { (*iter).bCheckDamage = true; } } } m_pOwner->NPlayAnimation( ANI_ATTACK01 ); SetStep( STEP_01 ); } else if( nStep == STEP_01 ) { float fRotation = 0.0f; if( (dwTime - m_dwOldTime) <= m_dwRotationTime ) { float fGap = (float)(dwTime - m_dwOldTime) / m_dwRotationTime; fRotation = m_fRangeAngle * fGap; } else { fRotation = m_fRangeAngle; SetEnd( true ); } K3DMatrix matResult, matRot, matTrans; K3DMatrixRotationZ( matRot, fRotation ); K3DMatrixTranslation( matTrans, m_vStartDir.x, m_vStartDir.y, m_vStartDir.z ); K3DMatrixMultiply( matResult, matTrans, matRot ); K3DVector vOut( matResult._41, matResult._42, matResult._43 ); K3DVectorNormalize( vOut, vOut ); std::vector< TargetInfo >::iterator iter = m_vTargetInfo.begin(); for( ; iter != m_vTargetInfo.end(); ) { SGameAvatarEx* pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( (*iter).hTarget ); if( pTarget ) { K3DVector vTarget; vTarget.x = pTarget->GetPosition()->x - m_pOwner->GetPosition()->x; vTarget.y = pTarget->GetPosition()->y - m_pOwner->GetPosition()->y; vTarget.z = 0.0f; K3DVectorNormalize( vTarget, vTarget ); if( CheckCrash( vOut, vTarget ) ) { //데미지 처리 pTarget->NPlayAnimation( ANI_DAMAGE01 ); iter = m_vTargetInfo.erase( iter ); } else { K3DVector vCross = CrossProduct( vOut, vTarget ); if( (*iter).bCheckDamage ) { if( vCross.z <= 0.0f ) { //데미지 처리 pTarget->NPlayAnimation( ANI_DAMAGE01 ); iter = m_vTargetInfo.erase( iter ); continue; } } else { if( vCross.z >= 0.0f ) { (*iter).bCheckDamage = true; } } ++iter; } } else { iter = m_vTargetInfo.erase( iter ); } } if( m_vTargetInfo.empty() ) SetEnd( true ); } } bool SWorkMultiAttack::CheckCrash( const K3DVector & vView, const K3DVector & vTarget ) { float fDot = DotProduct( vView, vTarget ); if( fDot >= m_fCheckAngle ) { return true; } return false; } //============================================================================================== //노동기술 SWorkingSkill::SWorkingSkill( class SGameAvatarEx * pOwner, _SKILL_FX* pSkillFX ) : SNewSkill( pOwner, pSkillFX ) , m_szSwapWeaponName( NULL ) , m_bHideWeapon( false ) { _MOTION_FX_SET* pFxSet = GetMotionFxSetDB().GetFXSet( pSkillFX->fStage_Data[0] ); if( pFxSet ) { m_szSwapWeaponName = GetResourceDB().GetEffectResourceName( pFxSet->graphic_effect_start_file_ID ); } else { if( pSkillFX->fStage_Data[1] != 0 ) { m_bHideWeapon = true; } } } SWorkingSkill::~SWorkingSkill() { } void SWorkingSkill::CastCancel() { ForceEnd(); if( GetSkillMode() == SKILLMODE_CAST ) { HideNSwapWeapon(); } } bool SWorkingSkill::ProcessingDamage() { return false; } void SWorkingSkill::Process( DWORD dwTime ) { m_dwTime = dwTime; if( IsEnd() ) return; // Fraun performance tweak m_pTarget = (SGameAvatarEx*)m_pOwner->GetGameObject( m_hTarget ); if( !m_pTarget ) { HideNSwapWeapon(); m_pOwner->Default(); SetEnd(true); return; } int nSkillMode = GetSkillMode(); switch (nSkillMode) { case SKILLMODE_CAST: { int nStep = GetStep(); switch (nStep) { case STEP_00: { if (m_bHideWeapon) { m_pOwner->HideWeapon(FALSE); } else { if (m_szSwapWeaponName != NULL) { m_pOwner->AddMeshPart(ANIPART_WEAPON_LEFT, MPART_L_WEAPON, ""); m_pOwner->AddMeshPart(ANIPART_WEAPON_RIGHT, MPART_R_WEAPON, m_szSwapWeaponName); } } _processDefCast(dwTime); break; } } break; } case SKILLMODE_FIRE: { int nStep = GetStep(); switch (nStep) { case STEP_00: { if (m_nFireMotionID != 0) { bool bPlayNextAnimation = false; int nAniType = m_pOwner->GetCurrentlyAniType(); if (nAniType == SEQTYPE_NORMAL || nAniType == SEQTYPE_LASTPAGE || nAniType == SEQTYPE_REVERSE) { if (!m_pOwner->IsPlaying()) bPlayNextAnimation = true; } else { if (m_pOwner->CurrentlyAnimationIsLoopWrap()) bPlayNextAnimation = true; } if (bPlayNextAnimation) { m_pOwner->NPlayAnimation(m_nFireMotionID); //시전시 동반 되는 이펙트 if (m_pSkillFX->nFire_Fx_Set_Id != 0) _addEffect(m_pOwner->GetArID(), m_pOwner->GetArID(), m_pOwner->GetArID(), m_pSkillFX->nFire_Fx_Set_Id, EFFECT_POS_BOTTOM, SEQTYPE_NORMAL); _getEventSet(); SetStep(STEP_01); } } else { SetStep(STEP_01); } break; } case STEP_01: { if (m_nFireMotionID != 0) { if (m_pOwner->GetCurrAnimationID() == m_nFireMotionID && !m_pOwner->IsPlaying()) { //시전 연출 끝났음. SetStep(STEP_02); } } else if (m_nFireMotionID == 0) { //시전 모션 없음. SetStep(STEP_02); } break; } case STEP_02: { HideNSwapWeapon(); m_pOwner->EndUseSkill(m_pSkillFX->nID); m_pOwner->Default(); SetEnd(TRUE); break; } default: { if (m_pOwner->IsUseSkill_complete()) { if (m_nFireMotionID != 0 && m_pOwner->GetCurrAnimationID() != m_nFireMotionID) { HideNSwapWeapon(); SetEnd(TRUE); return; } } break; } } break; } } DWORD eventTime = ((dwTime - m_dwStartTime) * m_fPlayRate); _processEventSet( eventTime ); _processView(); } void SWorkingSkill::HideNSwapWeapon() { if( m_bHideWeapon ) { m_pOwner->HideWeapon( TRUE ); } else if (m_szSwapWeaponName != NULL) { int nRace = m_pOwner->GetInnRace(); int nSex = m_pOwner->GetInnSex(); std::string strRightHand = GetItemDB().GetFileName(nRace, nSex, m_pOwner->GetItemCode(ItemBase::WEAR_WEAPON), m_pOwner->GetItemLevel(ItemBase::WEAR_WEAPON)); std::string strLeftHand = GetItemDB().GetFileName(nRace, nSex, m_pOwner->GetItemCode(ItemBase::WEAR_SHIELD), m_pOwner->GetItemLevel(ItemBase::WEAR_SHIELD)); strRightHand += ".nx3"; strLeftHand += ".nx3"; ItemBase::ItemClass nRItemClass = m_pOwner->GetItemClass(ItemBase::WEAR_WEAPON); if (nRItemClass == ItemBase::CLASS_LIGHT_BOW || nRItemClass == ItemBase::CLASS_HEAVY_BOW) { m_pOwner->AddMeshPart(ANIPART_WEAPON_RIGHT, MPART_R_WEAPON, ""); m_pOwner->AddMeshPart(ANIPART_WEAPON_LEFT, MPART_L_WEAPON, strRightHand.c_str()); } <<<<<<< HEAD else if (nRItemClass == ItemBase::CLASS_CROSSBOW) //Double Crossbow ======= // AziaMafia Double Crossbow // From ZONE source; dual crossbows else if (nRItemClass == ItemBase::CLASS_CROSSBOW) >>>>>>> a34328224e914a577b99c79ec6e8ffbcea554a05 { m_pOwner->AddMeshPart(ANIPART_WEAPON_RIGHT, MPART_R_WEAPON, strRightHand.c_str()); m_pOwner->AddMeshPart(ANIPART_WEAPON_LEFT, MPART_L_WEAPON, ""); } else { m_pOwner->AddMeshPart( ANIPART_WEAPON_RIGHT, MPART_R_WEAPON, strRightHand.c_str() ); ItemBase::ItemClass nLItemClass = m_pOwner->GetItemClass( ItemBase::WEAR_SHIELD ); if( nLItemClass == ItemBase::CLASS_ONEHAND_SWORD || nLItemClass == ItemBase::CLASS_DAGGER || nLItemClass == ItemBase::CLASS_ONEHAND_AXE) // From ZONE source; dual crossbows //if( nLItemClass == ItemBase::CLASS_ONEHAND_SWORD || nLItemClass == ItemBase::CLASS_DAGGER || nLItemClass == ItemBase::CLASS_ONEHAND_AXE || nLItemClass == ItemBase::CLASS_CROSSBOW) { if( strLeftHand.length() > 5 ) strLeftHand.replace( strLeftHand.size() - 4, 1, "_L." ); } m_pOwner->AddMeshPart( ANIPART_WEAPON_LEFT, MPART_L_WEAPON, strLeftHand.c_str() ); } m_pOwner->RefreshDeform(); } }