#include "stdafx.h" #include "SGameCreature.h" #include "KSeqAvatarEx.h" #include "SCreatureDB.h" #include "SSkillDB.h" //#include "Util.h" #include "SGameAniType.h" #include "SGameWork.h" #include "SGameMessage.h" #include "SSkillStageType.h" #include "SGameUtil.h" #include "SMonsterDB.h" #include "SAvatarProperty.h" #include "SDebug_Util.h" #include "SMotionDB.h" #include "KSeqAvatar.h" #include "SUIChattingWnd.h" SGameCreature::SGameCreature( ENC_INT nCreatureID, unsigned char ucEnhance ) : SGameAvatarEx(nCreatureID) , m_dwIdleTime( 0 ) // sonaodr 1.8.13 아바타 IDLE 모션 동작 구현 , m_ucEnhance( ucEnhance ) // floyd 2010. 4. 14 크리쳐 강화 { m_bIsUseSkill_complete = true; m_nCreatureRideType = 0; m_fPlayRate = DEFAULT_ANI_PLAY_RATE; m_fStandardWalkPlayRate = DEFAULT_ANI_PLAY_RATE; m_fStandardRunPlayRate = DEFAULT_ANI_PLAY_RATE; m_fRdbScale = 1.0f; m_fWalkSpeed = (float)DEF_SPEED; _SUMMON_INFO_FILE* pSummonInfo = GetCreatureDB().GetCreatureData( nCreatureID ); if( pSummonInfo ) { m_fStandardWalkPlayRate = (float)pSummonInfo->standard_walk_speed / 7.0f; m_fStandardRunPlayRate = (float)pSummonInfo->standard_run_speed / 7.0f; m_fRdbScale = pSummonInfo->scale; m_fWalkSpeed = (float)((pSummonInfo->standard_walk_speed + pSummonInfo->standard_run_speed) / 2.0f) / 7.0f; SetScale( pSummonInfo->scale ); } } SGameCreature::~SGameCreature() { } void SGameCreature::OnNetInput( struct SGameMessage * pMsg ) { if( !m_pStateVM ) return; m_pStateVM->OnNetInput( pMsg ); } AR_UNIT SGameCreature::GetSize() { // AziaMafia SKin pet if (m_pProperty->InnContentID()) { return GetCreatureDB().GetSize(m_pProperty->InnContentID()) ; } else return GetCreatureDB().GetSize(m_pProperty->ContentID()) ; } AR_UNIT SGameCreature::GetScale() { return m_fScale; // sonador 1.8.16 크리쳐 스케일 오류 수정 } // state void SGameCreature::OnChangeState( SObjectState::ID stateid, const SStateInfo &info ) { if( m_pStateVM == NULL ) return; AR_HANDLE target = m_pStateVM->GetCurrentStateInfo().hTarget; switch( stateid ) { case SObjectState::STATE_IDLE : { if( GetCurrAnimationID() == ANI_RUN || GetCurrAnimationID() == ANI_WALK ) { Default(); } if( !IsPlaying() && ( CurrentlyAnimationIsAttack() || CurrentlyAnimationIsDamage() ) ) Default(); break; //기본 상태 } case SObjectState::STATE_ATTACK : { // _oprint( "공격 상태 시간 : %d\n", m_dwTime ); SetViewVector( info.vTargetPos ); //몸통 방향 바꾸기 //일반 공격 OnAttack( info ); } break; // 공격 (1회) case SObjectState::STATE_MOVE : { if( info.dwSpeed == 0 ) { //달리다 죽은 것이므로 Ani 처리는 스킵한다. return; } //SetViewVector( info.vTargetPos ); SetAniLock( false ); if(info.dwSpeed < m_fWalkSpeed) { CalcCreatureWalkPlayRate( (float)info.dwSpeed ); Walk(true); } else { CalcCreatureRunPlayRate( (float)info.dwSpeed ); Run(); } } break; // 이동 case SObjectState::STATE_CHASE : if( info.dwSpeed >= m_fWalkSpeed ) { CalcCreatureRunPlayRate( (float)info.dwSpeed ); Run(); } else { CalcCreatureWalkPlayRate( (float)info.dwSpeed ); Walk(true); } SetViewVector( info.vTargetPos ); break; // 추격 case SObjectState::STATE_MOUNT : SetUnHold(); break; case SObjectState::STATE_CAST : { //_oprint( "SKILL - SObjectState::STATE_CAST\n" ); //_oprint( "*****상태 머신 : 캐스팅\n" ); m_bIsUseSkill_complete = false; //캐스팅 표시 if( IsLocalCreature() ) UseSkill( GetArID(), info.nSkillID, info.nSkillLv, info.dwSpeed ); //캐스팅 관련 연출 설정 //1) 애니메이션 연출 -> 설정 된 애니메이션의 이벤트 핸들 처리 //2) FX 출력 //New Process _SKILL_FX* pSkillFXDB = GetSkillStageDB().GetSkillStageData( info.nSkillID ); if( !pSkillFXDB ) { _oprint( "스킬 연출 데이타 없음!!! [스킬ID:%d]\n", info.nSkillID ); // assert( 0 && "스킬 연출 데이타 없음!!!" ); return; } _SKILL_FX* pSkillFX = new _SKILL_FX; *pSkillFX = *pSkillFXDB; float fRate = 1.f; if( pSkillFX->nCasting_Type_Id != 1 && (pSkillFX->nCasting_Start_Motion_Id !=0 || pSkillFX->nCasting_Middle_Motion_Id != 0) ) { pSkillFX->nCasting_Start_Motion_Id = 110; pSkillFX->nCasting_Middle_Motion_Id = 111; std::string strAniKey; int nBoneCount = 0; DWORD dwMinTime, dwMaxTime, totalTime; dwMinTime = 0; dwMaxTime = 0; totalTime = 0; if( pSkillFX->nCasting_Start_Motion_Id != 0 ) { strAniKey = GetAniKey( GetObjType(), pSkillFX->nCasting_Start_Motion_Id, true ); if( m_pSeqAvatar ) m_pSeqAvatar->GetFrameInfo( ANIPART_BIPED, strAniKey.c_str(), nBoneCount, dwMinTime, dwMaxTime ); totalTime = dwMaxTime; } if( pSkillFX->nCasting_Middle_Motion_Id ) { strAniKey = GetAniKey( GetObjType(), pSkillFX->nCasting_Middle_Motion_Id, true ); if( m_pSeqAvatar ) m_pSeqAvatar->GetFrameInfo( ANIPART_BIPED, strAniKey.c_str(), nBoneCount, dwMinTime, dwMaxTime ); totalTime += dwMaxTime; } float fAttack = GetAttackSpeed( info.dwSpeed*10 ); //기본 배율 fRate = GetAniPlayRate( fAttack, totalTime, false ); } else if( pSkillFX->nCasting_Type_Id == 1 ) { pSkillFX->nCasting_Start_Motion_Id = 70; pSkillFX->nCasting_Middle_Motion_Id = 80; } //switch( pSkillFX->nCasting_Type_Id ) //{ //case _SKILL_FX::SKILLTYPE_NOACT : break; //case _SKILL_FX::SKILLTYPE_MAGIC : break; //case _SKILL_FX::SKILLTYPE_INSTANT : break; //case _SKILL_FX::SKILLTYPE_INSTANT_CONTINUE : break; //case _SKILL_FX::SKILLTYPE_CHARGE : break; //case _SKILL_FX::SKILLTYPE_CHARGE_CONTINUE : break; //} //pSkillFX->nCasting_Start_Motion_Id; //시작 //pSkillFX->nCasting_Middle_Motion_Id; //시작 Loop SNewSkill * pSkill_Cast = NULL; SGameAvatarEx * pTarget = NULL; if( info.hTarget ) { pTarget = (SGameAvatarEx *)GetGameObject( info.hTarget ); } switch( pSkillFX->nStage_Type_Id ) { case SS_TYPE_001 : { SWorkSummonCall * pSkill = new SWorkSummonCall( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_002 : { SWorkSummonReCall * pSkill = new SWorkSummonReCall( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_101 : { SWorkWeaponSwingHit * pSkill = new SWorkWeaponSwingHit( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_111 : { SWorkShieldSwingHit * pSkill = new SWorkShieldSwingHit( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_121 : { SWorkWeaponSwing_3Motion * pSkill = new SWorkWeaponSwing_3Motion( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_122 : { SWorkWeaponSwing_ContinuousHits * pSkill = new SWorkWeaponSwing_ContinuousHits( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_123 : { SWorkWeaponSwing_Zeal * pSkill = new SWorkWeaponSwing_Zeal( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_151 : { SWorkWeaponSwing_Leech * pSkill = new SWorkWeaponSwing_Leech( this, pSkillFX ); pSkill_Cast = pSkill; } break; // case SS_TYPE_171 : { //TODO : 밀기 - 서버 메세지 처리 넣어야 함. SWorkRush_Shove* pSkill = new SWorkRush_Shove( this, pSkillFX ); pSkill_Cast = pSkill; } break; //// case SS_TYPE_172 : { break; //// case SS_TYPE_173 : { break; //// case SS_TYPE_174 : { break; case SS_TYPE_201 : { SWorkBowShoot* pSkill = new SWorkBowShoot( this, pSkillFX ); pSkill_Cast = pSkill; fRate = 1.f; } break; case SS_TYPE_212 : { SWorkBowShoot* pSkill = new SWorkBowShoot( this, pSkillFX ); pSkill_Cast = pSkill; fRate = 1.f; } break; case SS_TYPE_251 : { SWorkBowShoot* pSkill = new SWorkBowShoot( this, pSkillFX ); pSkill_Cast = pSkill; fRate = 1.f; } break; //// case SS_TYPE_211 : { break; // case SS_TYPE_212 : { SWorkBowShoot_Shove * pSkill = new SWorkBowShoot_Shove( this, pSkillFX ); pSkill_Cast = pSkill; } break; // case SS_TYPE_251 : { SWorkBowShoot_Leech * pSkill = new SWorkBowShoot_Leech( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_301 : { SWorkSelf * pSkill = new SWorkSelf( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_401 : case SS_TYPE_404 : { SWorkMotion * pSkill = new SWorkMotion( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_402 : { SWorkMotion_Leech * pSkill = new SWorkMotion_Leech( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_403 : { SWorkMotion_SummonMotion_Leech * pSkill = new SWorkMotion_SummonMotion_Leech( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_411 : { SWorkMotion_FXMotion * pSkill = new SWorkMotion_FXMotion( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_412 : { SWorkMotion_FXMotionMultiple * pSkill = new SWorkMotion_FXMotionMultiple( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_501 : { SWorkShoot_FXShoot * pSkill = new SWorkShoot_FXShoot( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_502 : { SWorkShoot_FXShootMultiple * pSkill = new SWorkShoot_FXShootMultiple( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_503 : { SWorkShoot_FXShootPenetrate * pSkill = new SWorkShoot_FXShootPenetrate( this, pSkillFX ); pSkill_Cast = pSkill; } break; /// 2011.03.23 - prodongi case SS_TYPE_504 : { SWorkShoot_FXShootChain * pSkill = new SWorkShoot_FXShootChain( this, pSkillFX ); pSkill_Cast = pSkill; } break; case SS_TYPE_601 : { SWorkGround_FXContinue * pSkill = new SWorkGround_FXContinue( this, pSkillFX ); pSkill_Cast = pSkill; } break; // case SS_TYPE_602 : break; // case SS_TYPE_603 : break; // case SS_TYPE_701 : break; default: { _oprint( "This skill is on hold. Please check with the planning team whether it should be used, and then confirm with the programming team whether it will be implemented.\n" ); // assert( 0 && "구현 보류 중인 스킬입니다.기획팀에 사용 여부를 확인 후, 프로그램 팀에 구현 여부를 확인 바랍니다.\n" ); } break; } if( pSkill_Cast ) { //변경 되었으면, PlayRate 수정 if( fRate != 1.f && pSkillFX->nCasting_Type_Id != 1 ) //마법류는 PlayRate 수정 하지 않는다. pSkill_Cast->SetPlayRate( fRate/4.8f ); if( pTarget ) { pSkill_Cast->SetTarget( info.hTarget, pTarget ); // 2010.05.25 - prodongi //흡수체 스킬류 if(pSkillFX->nStage_Type_Id == SS_TYPE_402 ) { //대상이 삭제될수 있으이 보류시킨다 pTarget->SetReservation(true); } } pSkill_Cast->SetStartTime( m_dwTime ); pSkill_Cast->SetSkillMode( SNewSkill::SKILLMODE_CAST ); m_vCastSkillList.push_back( pSkill_Cast ); m_nWeaponSwing_RepeatMotion = 0; } else SAFE_DELETE( pSkillFX ); break; // 캐스팅 } case SObjectState::STATE_FIRE : { //_oprint( "SKILL - SObjectState::STATE_FIRE\n" ); // _oprint( "*****상태 머신 : 발사\n" ); //SkillResult가 0이면 Fire실패 Default모션으로 if(info.vSkillResult.empty()) { m_bIsUseSkill_complete = true; for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) m_vCastSkillList[i]->ForceEnd(); SetAniLock( false ); Default(); return; } //New Process //Cast 관련 사운드 끄기 //Cast 관련 이펙트 끄기 _SKILL_FX* pSkillFXDB = GetSkillStageDB().GetSkillStageData( info.nSkillID ); if( !pSkillFXDB ) { _oprint( "스킬 연출 데이타 없음!!! [스킬ID:%d]\n", info.nSkillID ); // assert( 0 && "스킬 연출 데이타 없음!!!" ); return; } _SKILL_FX* pSkillFX = new _SKILL_FX; *pSkillFX = *pSkillFXDB; if( pSkillFX->nCasting_Type_Id == 1 ) pSkillFX->nFire_Motion_Id = 90; else pSkillFX->nFire_Motion_Id = 112; SNewSkill * pSkill_Fire = NULL; SGameAvatarEx * pTarget = NULL; if( info.hTarget ) { pTarget = (SGameAvatarEx *)GetGameObject( info.hTarget ); } switch( pSkillFX->nStage_Type_Id ) { case SS_TYPE_001 : { SWorkSummonCall * pSkill = new SWorkSummonCall( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_002 : { SWorkSummonReCall * pSkill = new SWorkSummonReCall( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_101 : { SWorkWeaponSwingHit * pSkill = new SWorkWeaponSwingHit( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_111 : { SWorkShieldSwingHit * pSkill = new SWorkShieldSwingHit( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_121 : { SWorkWeaponSwing_3Motion * pSkill = new SWorkWeaponSwing_3Motion( this, pSkillFX ); pSkill_Fire = pSkill; pSkill->SetCurHitCount( m_nWeaponSwing_RepeatMotion ); } break; case SS_TYPE_122 : { SWorkWeaponSwing_ContinuousHits * pSkill = new SWorkWeaponSwing_ContinuousHits( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_123 : { SWorkWeaponSwing_Zeal * pSkill = new SWorkWeaponSwing_Zeal( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_151 : { SWorkWeaponSwing_Leech * pSkill = new SWorkWeaponSwing_Leech( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_171 : break; // sonador 11.0.1 돌진 스킬 연출 오류 수정 // case SS_TYPE_171 : { //TODO : 밀기 - 서버 메세지 처리 넣어야 함. SWorkRush_Shove* pSkill = new SWorkRush_Shove( this, pSkillFX ); pSkill_Fire = pSkill; } break; // case SS_TYPE_172 : { break; // case SS_TYPE_173 : { break; // case SS_TYPE_174 : { break; case SS_TYPE_201 : { SWorkBowShoot* pSkill = new SWorkBowShoot( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_212 : { SWorkBowShoot* pSkill = new SWorkBowShoot( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_251 : { SWorkBowShoot* pSkill = new SWorkBowShoot( this, pSkillFX ); pSkill_Fire = pSkill; } break; // case SS_TYPE_211 : { break; // case SS_TYPE_212 : { SWorkBowShoot_Shove * pSkill = new SWorkBowShoot_Shove( this, pSkillFX ); pSkill_Fire = pSkill; } break; // case SS_TYPE_251 : { SWorkBowShoot_Leech * pSkill = new SWorkBowShoot_Leech( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_301 : { SWorkSelf * pSkill = new SWorkSelf( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_401 : case SS_TYPE_404 : { SWorkMotion * pSkill = new SWorkMotion( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_402 : { SWorkMotion_Leech * pSkill = new SWorkMotion_Leech( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_403 : { SWorkMotion_SummonMotion_Leech * pSkill = new SWorkMotion_SummonMotion_Leech( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_411 : { SWorkMotion_FXMotion * pSkill = new SWorkMotion_FXMotion( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_412 : { SWorkMotion_FXMotionMultiple * pSkill = new SWorkMotion_FXMotionMultiple( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_501 : { SWorkShoot_FXShoot * pSkill = new SWorkShoot_FXShoot( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_502 : { SWorkShoot_FXShootMultiple * pSkill = new SWorkShoot_FXShootMultiple( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_503 : { SWorkShoot_FXShootPenetrate * pSkill = new SWorkShoot_FXShootPenetrate( this, pSkillFX ); pSkill_Fire = pSkill; } break; /// 2011.03.23 - prodongi case SS_TYPE_504 : { SWorkShoot_FXShootChain * pSkill = new SWorkShoot_FXShootChain( this, pSkillFX ); pSkill_Fire = pSkill; } break; case SS_TYPE_601 : { SWorkGround_FXContinue * pSkill = new SWorkGround_FXContinue( this, pSkillFX ); pSkill_Fire = pSkill; } break; // case SS_TYPE_602 : break; // case SS_TYPE_603 : break; // case SS_TYPE_701 : break; default: { _oprint( "구현 보류 중인 스킬입니다.기획팀에 사용 여부를 확인 후, 프로그램 팀에 구현 여부를 확인 바랍니다.\n" ); // assert( 0 && "구현 보류 중인 스킬입니다.기획팀에 사용 여부를 확인 후, 프로그램 팀에 구현 여부를 확인 바랍니다.\n" ); SAFE_DELETE( pSkillFX ); return; } break; } if( pSkillFX->nStage_Type_Id == SS_TYPE_121 ) { //최대 연타 수 ( DB에 정의됨 ) if( m_nWeaponSwing_RepeatMotion < pSkillFXDB->fStage_Data[9] ) ++m_nWeaponSwing_RepeatMotion; else m_nWeaponSwing_RepeatMotion = 0; } else m_nWeaponSwing_RepeatMotion = 0; if( pSkill_Fire ) { //SAction에서 데미지 처리하고 있기 때문에 데미지 표시가 2번뜬다 switch( pSkillFX->nStage_Type_Id ) { case SS_TYPE_001 : case SS_TYPE_002 : case SS_TYPE_101 : case SS_TYPE_111 : case SS_TYPE_121 : case SS_TYPE_122 : case SS_TYPE_123 : pSkill_Fire->SetDamegeInfo( &info ); break; // AziaMAfiaSkillFix Animation /*default: pSkill_Fire->SetActionSkillEvent( &info ); break;*/ } //돌고 있는 케스팅은 모두 강제 끝 for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) m_vCastSkillList[i]->ForceEnd(); if( pSkillFX->nCasting_Type_Id == 1 ) //마법류 스킬이면 { //5번 타인에게 사용하는 해로운 스킬 pSkill_Fire->SetFireMotionID( 90 ); //나쁜 스킬 설정 //1번 소환/역소환 스킬이면 if( pSkillFX->nStage_Type_Id == 1 || pSkillFX->nStage_Type_Id == 2 ) pSkill_Fire->SetFireMotionID( 94 ); //소환 스킬은 없을듯 else { SkillBaseEx * pSkill = GetSkillDB().GetSkillData( info.nSkillID ); if( pSkill ) { //2번 자신에게만 주는 이로운 스킬 if( (pSkill->GetSkillTargetType() == 1 || pSkill->GetSkillTargetType() == 4 || pSkill->GetSkillTargetType() == 31 ) && info.hTarget == GetArID() ) { pSkill_Fire->SetFireMotionID( 90 ); } else { //3번 자신의 주변에 영향을 주는 스킬 if( info.hTarget == GetArID() ) pSkill_Fire->SetFireMotionID( 90 ); else { //4번 타인에게 사용하는 이로운 스킬 if( !pSkill->IsHarmful() ) pSkill_Fire->SetFireMotionID( 90 ); } } } } } if( pTarget ) pSkill_Fire->SetTarget( info.hTarget, pTarget ); pSkill_Fire->SetStartTime( m_dwTime ); pSkill_Fire->SetSkillMode( SNewSkill::SKILLMODE_FIRE ); m_vFireSkillList.push_back( pSkill_Fire ); } else { if( pSkillFX->nStage_Type_Id != SS_TYPE_171 ) { SAFE_DELETE( pSkillFX ); return; } } //RUSH, KNOCK_BACK, DAMAGE 처리 if( pSkillFX->nStage_Type_Id != SS_TYPE_171 ) return; std::vector::const_iterator it; for( it = info.vSkillResult.begin(); it != info.vSkillResult.end(); it++ ) { _SKILL_FX* ptSkillFX = new _SKILL_FX; *ptSkillFX = *pSkillFXDB; if( SkillResult::RUSH == (*it).GetType() ) { if( (*it).rush.bResult ) { SWorkRush_Shove* pRushShove = new SWorkRush_Shove( this, ptSkillFX, &info ); m_vFireSkillList.push_back( pRushShove ); return; } } else if( SkillResult::DAMAGE_WITH_KNOCK_BACK == (*it).GetType() ) { SWorkKnockBack* pWorkKnockBack = new SWorkKnockBack( this, ptSkillFX, &(*it) ); pWorkKnockBack->SetStartTime( m_dwTime ); m_vFireSkillList.push_back( pWorkKnockBack ); } else if( SkillResult::DAMAGE == (*it).GetType() ) { SChargeAttack* pChargerAttack = new SChargeAttack( this, ptSkillFX, &(*it) ); pChargerAttack->SetStartTime( m_dwTime ); m_vFireSkillList.push_back( pChargerAttack ); } } } break; // 캐스팅 case SObjectState::STATE_SKILL_END : { //_oprint( "SKILL - SObjectState::STATE_SKILL_END\n" ); m_bIsUseSkill_complete = true; for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) m_vCastSkillList[i]->ForceEnd(); // for( unsigned int i(0); m_vFireSkillList.size()>i; i++ ) // m_vFireSkillList[i]->ForceEnd(); break; } case SObjectState::STATE_CAST_CANCEL : { //_oprint( "SKILL - SObjectState::STATE_CAST_CANCEL\n" ); m_bIsUseSkill_complete = true; for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) m_vCastSkillList[i]->ForceEnd(); // for( unsigned int i(0); m_vFireSkillList.size()>i; i++ ) // m_vFireSkillList[i]->ForceEnd(); Default(); break; } } } bool SGameCreature::MotionCancel() { if( m_vAttackEventList.empty() && m_vCastSkillList.empty() && m_vFireSkillList.empty() ) { m_bIsUseSkill_complete = true; SetIng(false); SetAniLock( false ); Default(); return true; } //애니메이션 진행과 상관없이 히트 후 바로 캔슬 가능 /* int nBoneCnt = 0; DWORD dwMinTime = 0, dwMaxTime = 0; DWORD dwCurAniTime = 0; GetCurrentAnimationInfo( nBoneCnt, dwMinTime, dwMaxTime, dwCurAniTime ); dwMaxTime = dwMaxTime / 160; dwCurAniTime = (dwCurAniTime / 160) * 4.8f; float fPlayProgress = (dwCurAniTime / (float)dwMaxTime); //80프로 애니메이션 진행되면 모션 캔슬 가능 if( fPlayProgress < 0.13f ) return; */ //데미지 처리 완료했는지 체크 for( unsigned int i(0); m_vAttackEventList.size()>i; i++) { if( !m_vAttackEventList[i]->ProcessingDamage() ) return false; } for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) { if( !m_vCastSkillList[i]->ProcessingDamage() ) return false; } for( unsigned int i(0); m_vFireSkillList.size()>i; i++ ) { if( !m_vFireSkillList[i]->ProcessingDamage() ) return false; } for( unsigned int i(0); m_vAttackEventList.size()>i; i++) m_vAttackEventList[i]->ForceEnd(); for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) m_vCastSkillList[i]->ForceEnd(); for( unsigned int i(0); m_vFireSkillList.size()>i; i++ ) m_vFireSkillList[i]->ForceEnd(); m_bIsUseSkill_complete = true; SetIng(false); SetAniLock( false ); Default(); return true; } void SGameCreature::SetMountMode() { if( m_pStateVM ) m_pStateVM->SetMode( SObjectStateMachine::MODE_MOUNT ); } void SGameCreature::SetAttackMode() { if( m_pStateVM ) m_pStateVM->SetMode( SObjectStateMachine::MODE_ATTACK ); } void SGameCreature::SetNormalMode() { if( m_pStateVM ) m_pStateVM->SetMode( SObjectStateMachine::MODE_NORMAL ); } void SGameCreature::Damage() { if( _damage() ) { return; } //이미 공격 중이면, 모션 플레이 안됨. if( GetAttackAniLock() ) return; ////이동 중, 공격 중 에는 영향 안 받는다. if( GetCurrAnimationID() == ANI_WALK || GetCurrAnimationID() == ANI_RUN || GetCurrAnimationID() == ANI_DEAD01 ) return; if( GetCurrAnimationID() == ANI_DEFAULT01 || GetCurrAnimationID() == ANI_IDLE ) // sonaodr 1.8.13 아바타 IDLE 모션 동작 구현 NPlayAnimation( ANI_DAMAGE01, SEQTYPE_NORMAL ); if( GetCurrAnimationID() == ANI_DAMAGE01 && !IsPlaying() ) { NPlayAnimation( ANI_DAMAGE01, SEQTYPE_NORMAL ); } else if( GetCurrAnimationID() == ANI_DAMAGE02 && !IsPlaying() ) { NPlayAnimation( ANI_DAMAGE02, SEQTYPE_NORMAL ); } } void SGameCreature::Default( bool bForce/*=false*/ ) { // if( GetHP() <= 0 ) // return; if( CurrentlyAnimationIsAttack() && IsPlaying() ) return; // sonador 1.8.8 크리쳐 전투중 디폴트 모션 개선 if( m_pStateVM->GetMode() == SObjectStateMachine::MODE_ATTACK ) { if( GetCurrAnimationID() != ANI_DEFAULT02 ) NPlayAnimation( ANI_DEFAULT02, SEQTYPE_LOOP ); } else if( m_pStateVM->GetMode() == SObjectStateMachine::MODE_NORMAL ) { // _resetIdleTime(); // sonaodr 1.8.13 아바타 IDLE 모션 동작 구현 if( GetCurrAnimationID() != ANI_DEFAULT01 ) NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); } else { if( GetCurrAnimationID() != ANI_DEFAULT01 ) NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); } } void SGameCreature::Walk( bool bLoop ) { if( GetCurrAnimationID() != ANI_WALK || m_fCurPlayRate != m_fPlayRate ) NPlayAnimation( ANI_WALK, SEQTYPE_LOOP, m_fPlayRate ); } void SGameCreature::Run( bool bAutoRun, int nAniType ) { if( GetCurrAnimationID() != nAniType || m_fCurPlayRate != m_fPlayRate ) NPlayAnimation( nAniType, SEQTYPE_LOOP, m_fPlayRate ); } // sonaodr 1.8.13 아바타 IDLE 모션 동작 구현 void SGameCreature::_processIdle() { if( GetCurrAnimationID() == ANI_IDLE ) { if( !IsPlaying() ) NPlayAnimation( ANI_DEFAULT01, SEQTYPE_LOOP ); } else if( GetCurrAnimationID() == ANI_DEFAULT01 ) { int timeDiff = m_dwTime - m_dwIdleTime; int rand = XFastRandom( 1, 10000000 ); if( rand < (int)timeDiff ) { NPlayAnimation( ANI_IDLE, SEQTYPE_NORMAL ); _resetIdleTime(); } } } bool SGameCreature::Process( DWORD time, unsigned long uProcessBitVector ) // sonador 1.8.15 다른 플레이어의 크리처 스킬 연출 오류 수정 { SGameAvatarEx::Process( time, uProcessBitVector ); _processIdle(); // sonaodr 1.8.13 아바타 IDLE 모션 동작 구현 if( !m_vCastSkillList.empty() ) CheckWorkDel( m_vCastSkillList ); if( !m_vFireSkillList.empty() ) CheckWorkDel( m_vFireSkillList ); for( unsigned int i(0); m_vCastSkillList.size()>i; i++ ) m_vCastSkillList[i]->Process( m_dwTime ); for( unsigned int i(0); m_vFireSkillList.size()>i; i++ ) m_vFireSkillList[i]->Process( m_dwTime ); return true; } void SGameCreature::SetViewVectorForMount( const K3DVector &tpos ) { m_fTargetRoll = atan2( tpos.y, tpos.x ); m_dwPrevTime = m_dwTime; m_bUseRot = true; StandingDegreeForMount(); } void SGameCreature::CalcCreatureRunPlayRate( float fSpeed ) { //#ifdef _DEBUG m_fPlayRate = DEFAULT_ANI_PLAY_RATE * ( (fSpeed / m_fStandardRunPlayRate) / m_fRdbScale ); //#else // m_fPlayRate = DEFAULT_ANI_PLAY_RATE; //#endif } void SGameCreature::CalcCreatureWalkPlayRate( float fSpeed ) { //#ifdef _DEBUG m_fPlayRate = DEFAULT_ANI_PLAY_RATE * ( (fSpeed / m_fStandardWalkPlayRate) / m_fRdbScale ); //#else // m_fPlayRate = DEFAULT_ANI_PLAY_RATE; //#endif } bool SGameCreature::ExistAnimation( int ani_id) { const char * pAni = NULL; if( GetInnObjType() == TS_ENTER::GAME_SUMMON) { //몹디비에서 해당 모션의 이름을 꺼내본다 _MONSTER_INFO_FILE * pMonster = GetMonsterDB().GetMonsterData( GetInnContentID() ); if( pMonster ) pAni = GetMonsterMotionSetDB().GetAni( pMonster->motion_file_id, ani_id ); if (pAni != NULL) { std::string strAniKey; KSeqObject* ani = NULL; CStringUtil::GetStrKey( pAni, '_', strAniKey ); // 여기까지 해서 모션의 이름을 꺼내본뒤에 // 아래에서 아바타의 BIPED 부분에서 그 애니메이션이 있는지 꺼내본다 if (m_pSeqAvatar != NULL) ani = m_pSeqAvatar->getAvatarPart(ANIPART_BIPED)->GetAnimation( strAniKey.c_str() ); if ( ani == NULL) return false; else return true; } else return false; } return true; } int SGameCreature::GetAnimationLength(int ani_id) { const char * pAni = NULL; if( GetInnObjType() == TS_ENTER::GAME_SUMMON) { //몹디비에서 해당 모션의 이름을 꺼내본다 _MONSTER_INFO_FILE * pMonster = GetMonsterDB().GetMonsterData( GetInnContentID() ); if( pMonster ) pAni = GetMonsterMotionSetDB().GetAni( pMonster->motion_file_id, ani_id ); std::string strAniKey; KSeqObject* new_ani = NULL; if (pAni != NULL) { CStringUtil::GetStrKey( pAni, '_', strAniKey ); // 여기까지 해서 모션의 이름을 꺼내본뒤에 // 아래에서 아바타의 BIPED 부분에서 그 애니메이션이 있는지 꺼내본다 if (m_pSeqAvatar != NULL) new_ani = m_pSeqAvatar->getAvatarPart(ANIPART_BIPED)->GetAnimation( strAniKey.c_str() ); } if (new_ani == NULL) // 없으면 -1 { return -1; } else // 있으면 { return new_ani->GetInterval().GetLength(); } } return -1; } void SGameCreature::RefreshTextureGroup( vec_cobset* pCobSet ) { if (pCobSet == NULL || m_pSeqAvatar == NULL || pCobSet->empty()) return; assert(GetInnObjType() == TS_ENTER::GAME_SUMMON); _SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID()); if (pSummon == NULL) return; int texture_group_index = pSummon->texture_group; if (m_ucEnhance > 0) { if (ENV().IsExist("c_enhance")) { texture_group_index = m_ucEnhance; } else { texture_group_index = 1; } EnableMTE(true); } _RefreshTextureGroup(texture_group_index, pCobSet); } /* { if ( pCobSet == NULL || m_pSeqAvatar == NULL || pCobSet->empty() ) return; assert( GetInnObjType() == TS_ENTER::GAME_SUMMON ); _SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData( GetInnContentID() ); if( pSummon == NULL ) return; int texture_group_index = pSummon->texture_group; // sonador 1.8.10 아바타 텍스쳐 그룹 적용(페이스 컷 포함) /* AziaMafia MTE backup if (m_ucEnhance > 0) // floyd 2010. 4. 14 크리쳐 강화, 강화된 크리쳐의 텍스쳐 변경 { texture_group_index = 1; //gmpbigsun( 2012_1213 ) : mte적용 // AziaMafia MTE EnableMTE(true); } //Edit texture_group_index = m_ucEnhance ; if (m_ucEnhance == 5 ) { EnableMTE(true); } */ /* if (m_ucEnhance > 0 ) // floyd 2010. 4. 14 크리쳐 강화, 강화된 크리쳐의 텍스쳐 변경 { texture_group_index = 1; //gmpbigsun( 2012_1213 ) : mte적용 // AziaMafia MTE EnableMTE(true); } if (m_nDisguise == NONE_DISGUISE ) // m_disguiseEnhance _RefreshTextureGroup( texture_group_index, pCobSet ); // 크리처 강화시 텍스처를 다시 찾는다(0 -> 1 단계로 강화에만 텍스처 바뀜) servantes 2011.03.15 주석추가 } */