// // nDmgCnt : 일반적으론 0 : 지속데미지를 사용할경우에 0이 아닌값이 들어온다. // void CSfx::DamageToTarget( int nDmgCnt, float fDmgAngle, float fDmgPower, int nMaxDmgCnt ) { CMover* pObjSrc = (CMover*)prj.GetCtrl( m_idSrc ); CCtrl* pObjDest = prj.GetCtrl( m_idDest ); if( IsInvalidObj(pObjSrc) ) return; // 지금은 걍 리턴하지만 이렇게 실패한경우는 m_idSfxHit을 Clear해주는작업이 필요하다. if( IsInvalidObj(pObjDest) ) return; if( pObjDest->GetType() == OT_MOVER ) { CMover* pMover = (CMover*) pObjDest; #ifdef __CLIENT PLAYSND( pMover->GetProp()->dwSndDmg2, &pMover->GetPos() ); // 마법류 맞을때 타격음. #endif #ifdef __CLIENT // 쏜놈이 플레이어이거나 / 쏜놈은 플레이어가 아닌데 맞은놈이 플레이어일경우 전송 if( pObjSrc->IsActiveMover() || (pObjSrc->IsPlayer() == FALSE && pObjDest->IsActiveObj()) ) { pMover->SetDmgCnt( 10 ); // 발사체 맞아도 이제 흔들린다, g_DPlay.SendSfxHit( m_idSfxHit, m_nMagicPower, m_dwSkill, pObjSrc->GetId(), nDmgCnt, fDmgAngle, fDmgPower ); if( nMaxDmgCnt == 1 ) // 한방짜리 데미지만 id를 클리어 함. m_idSfxHit = 0; // 0으로 해놔야 this가 삭제될때 SendSfxClear를 또 보내지 않는다. } #endif // __CLIENT } }
void CPartyMng::PartyMapInfo( ) { const float PARTY_MAP_AROUND = 32.0f * 32.0f; // m_nVisibilityRange에 영향을 받는다. if( ++m_nSecCount < PARTY_MAP_SEC ) return; m_nSecCount = 0; D3DXVECTOR3 vPosBuf; float fDist; for( C2PartyPtr::iterator i = m_2PartyPtr.begin(); i != m_2PartyPtr.end(); ++i ) { CParty* pParty = (CParty*)i->second; for( int j = 0 ; j < pParty->GetSizeofMember() ; ++j ) { CMover* pMover = prj.GetUserByID( pParty->GetPlayerId( j ) ); if( !IsValidObj( pMover ) ) continue; vPosBuf = pMover->GetPos() - pParty->GetPos( j ); fDist = D3DXVec3LengthSq( &vPosBuf ); if( 0.0f < fDist ) { pParty->SetPos( j, pMover->GetPos() ); CMover* pSendMover; for( int k = 0 ; k < pParty->GetSizeofMember() ; ++k ) { if( k == j ) continue; pSendMover = prj.GetUserByID( pParty->GetPlayerId( k ) ); if( !IsValidObj( pSendMover ) ) continue; vPosBuf = pSendMover->GetPos() - pMover->GetPos(); fDist = D3DXVec3LengthSq( &vPosBuf ); if( fDist > PARTY_MAP_AROUND ) ((CUser*)pSendMover)->AddPartyMapInfo( j, pMover->GetPos() ); } } } } }
void CAIMonster2::InitAI() { CMover* pMover = GetMover(); MoverProp* pProperty = pMover->GetProp(); ASSERT( pProperty ); if( pProperty->dwAI >= AII_VER2_TYPE0 ) m_dwFsmType = pProperty->dwAI - AII_VER2_TYPE0; m_vPosBegin = pMover->GetPos(); m_fAttackRange = pMover->GetRadiusXZ(); }
void CAIMonster2::OnBeginState( int nInput, DWORD dwParam1, DWORD dwParam2 ) { CMover* pMover = GetMover(); switch( GetState() ) { case AI2_MOVE: { D3DXVECTOR3 vPos = m_vPosBegin; int x = xRandom( 20 ); int z = xRandom( 20 ); vPos.x += (float)(x - 10); vPos.z += (float)(z - 10); MoveToDst( vPos ); // y는 어떻게 되나? } break; case AI2_IDLE: //m_dwReattack = GetTickCount() + xRandom( 0, 2000 ); m_dwReattack = GetTickCount() + 2000; m_idTarget = NULL_ID; m_vTarget.x = m_vTarget.y = m_vTarget.z = 0.0f; pMover->SetStop(); MoveToDst( pMover->GetPos() ); break; case AI2_ATTACK: if( BeginAttack() == FALSE ) // 공격 SendAIMsg( AIMSG_END_MELEEATTACK, 0, 0 ); // 실패할 경우 공격완료 메세지는 오지 않는다. break; case AI2_TRACKING: if( m_idTarget == NULL_ID ) { m_idTarget = m_idLastAttacker; ASSERT( m_idTarget != NULL_ID ); } #ifdef __TRAFIC_1222 if( pMover->GetDestId() == m_idTarget ) break; #endif // __TRAFIC_1222 // 이동할 목표물을 idTarget으로 설정. pMover->SetDestObj( m_idTarget, m_fAttackRange ); g_UserMng.AddMoverSetDestObj( pMover, m_idTarget, m_fAttackRange ); break; case AI2_SEARCH: break; } }
// // 비행중 공격 액션 처리 // void CActionMover::_ProcessStateAttack2( DWORD dwState, int nParam ) { CMover* pMover = m_pMover; CModelObject *pModel = (CModelObject *)pMover->m_pModel; switch( dwState ) { case OBJSTA_ATK1: if( pModel->IsEndFrame() ) ResetState( OBJSTA_ATK_ALL ); if( pModel->m_nPause > 0 ) { --pModel->m_nPause; } else { if( pModel->IsAttrHit() ) { CMover* pHitObj = prj.GetMover( m_objidHit ); if( IsInvalidObj( pHitObj ) || pHitObj->IsDie() ) // 타겟이 거시기하거나 죽었으면 취소 return; BOOL bSuccess = pHitObj->m_pActMover->SendDamage( AF_GENERIC, pMover->GetId() ); if( bSuccess == FALSE ) return; #ifdef __CLIENT ItemProp* pItemProp = pMover->GetActiveHandItemProp(); if( pItemProp ) { D3DXVECTOR3 v = pMover->GetPos(); PLAYSND( pItemProp->dwSndAttack1, &v ); } #endif if( GetMover()->IsPlayer() ) { pModel->m_nPause = 5; // frame 멈춤 } else { pModel->m_nPause = 0; // 몬스터는 멈추지 않음 pHitObj->m_pModel->m_nPause = 0; } } } break; } }
FOR_LINKMAP( GetWorld(), vPos, pObj, nRange, CObj::linkPlayer, GetLayer() ) { if( pObj->GetType() == OT_MOVER ) // 대상이 무버일때만. { CMover *pTarget = (CMover *)pObj; if( pTarget->IsLive() && pAttacker != pTarget ) { if( pObj->IsRangeObj( vPos, 1.0f ) ) { #if __VER >= 9 // __SKILL_0706 int n = 0; if( bPVP && pAttacker->IsPVPTarget( pTarget ) ) n = pTarget->m_pActMover->SendDamage( AF_FORCE, pAttacker->GetId(), nDamagePVP, FALSE ); else if( bPVP && (m_bControl || pAttacker->IsGuildCombatTarget( pTarget ) /*아레나 추가*/ || pAttacker->IsArenaTarget( pTarget ) ) ) n = pTarget->m_pActMover->SendDamage( AF_FORCE, pAttacker->GetId(), nDamage, FALSE ); #else // __SKILL_0706 int n = pTarget->m_pActMover->SendDamage( AF_FORCE, pAttacker->GetId(), nDamage, FALSE ); #endif // __SKILL_0706 if( n > 0 ) { m_nLife ++; // 부딪힐때마다 카운트 올라감 if( m_nLife >= (int)( m_pAddSkillProp->dwSkillLvl / 2 ) ) DestroyWall(); // 뒤로 밀리기 처리. FLOAT fPushAngle = pTarget->GetAngle() + 180.0f; FLOAT fPower = 0.825f; AngleToVectorXZ( &pTarget->m_pActMover->m_vDeltaE, fPushAngle, fPower ); g_UserMng.AddPushPower( pTarget, pTarget->GetPos(), pTarget->GetAngle(), fPushAngle, fPower ); } } } } }
// // 오브젝트를 움직이는데 필요한 메시지를 발생 // int CWndWorld::ControlGround( DWORD dwMessage, CPoint point ) { bool fCastCancel = false; int nMsg = 0; BOOL bTempKey, bSit; // ,bCombatKey, bFlyKey BOOL bUp, bDown, bLeft, bRight, bSpace, bBoard, bLForward = FALSE, bRForward = FALSE; BOOL bWalk; static BOOL s_bWalk2 = 0; CMover* pMover = CMover::GetActiveMover(); CWndChat* pWndChat = (CWndChat*) g_WndMng.GetApplet( APP_COMMUNICATION_CHAT ); BOOL bWhisper = g_bKeyTable['R']; if( pWndChat && bWhisper ) { if( 0 < strlen( g_Neuz.m_szWhisperName ) ) { CString strWhisper; strWhisper.Format( "/whisper %s ", g_Neuz.m_szWhisperName ); pWndChat->SetFocus(); CWndEditChat* pWndEdit = &pWndChat->m_wndEdit; pWndEdit->SetString( strWhisper ); pWndEdit->SetFocus(); g_bKeyTable['R'] = FALSE; } } // 전진/후진/스톱 CWndBase* pWndBaseFocus = (CWndBase*) g_WndMng.GetFocusWnd(); if( g_Neuz.m_bActiveNeuz == FALSE || ( pWndChat && pWndBaseFocus && pWndBaseFocus == pWndChat ) ) { g_bKeyTable[g_Neuz.Key.chUp] = FALSE;// | m_bRButtonDown; g_bKeyTable[g_Neuz.Key.chLeft] = FALSE; g_bKeyTable['S'] = FALSE; g_bKeyTable['D'] = FALSE; g_bKeyTable['Q'] = FALSE; g_bKeyTable['E'] = FALSE; } bUp = g_bKeyTable[g_Neuz.Key.chUp]; // | m_bRButtonDown; bDown = g_bKeyTable['S']; #ifdef __BS_ADJUST_SYNC //gmpbigsun : 키보드 조작중에는 마우스이동 불가 if( bUp || bDown ) m_bLButtonDown = FALSE; #endif if( bDown ) { g_WndMng.m_bAutoRun = FALSE; } if( bUp ) { m_timerAutoRunPush.Reset(); if( m_nDubleUp == 2 && m_timerAutoRun.TimeOut() == FALSE ) { m_nDubleUp = 3; g_WndMng.m_bAutoRun = TRUE; m_timerAutoRun.Reset(); m_timerAutoRunBlock.Reset(); } else { m_nDubleUp = 1; m_timerAutoRun.Reset(); } if( m_timerAutoRunBlock.TimeOut() ) g_WndMng.m_bAutoRun = FALSE; } else { if( m_timerAutoRunPush.TimeOut() == FALSE ) { if( m_nDubleUp == 1 ) m_nDubleUp = 2; } else { m_nDubleUp = 0; } } if( g_WndMng.m_bAutoRun ) bUp = TRUE; // 좌/우 회전 bLeft = g_bKeyTable[g_Neuz.Key.chLeft]; bRight = g_bKeyTable['D']; bSpace = g_bKeyTable[ VK_SPACE ]; // bCombatKey = g_bKeyTable['C']; // g_bKeyTable['C'] = 0; bBoard = g_bKeyTable['B']; bSit = g_bKeyTable['V']; g_bKeyTable['V'] = 0; /* if( g_Option.m_nInterface == 2 ) { bLForward = g_bKeyTable['Q']; bRForward = g_bKeyTable['E']; if( m_bLButtonDown ) { if( bLeft ) { bLeft = FALSE; bLForward = TRUE; } if( bRight ) { bRight = FALSE; bRForward = TRUE; } } } */ CWorld* pWorld = g_WorldMng.Get(); CRect rect = GetClientRect(); D3DXVECTOR3 vRayEnd; CObj* pFocusObj = pWorld->GetObjFocus(); CActionMover *pAct = pMover->m_pActMover; pAct->m_dwCtrlMsg = 0; if( m_bLButtonDown ) pAct->m_dwCtrlMsg |= CTRLMSG_LDOWN; #if __VER >= 12 // __ITEMCREATEMON_S0602 D3DXVECTOR3 vec3Tri[3]; pWorld->ClientPointToVector( vec3Tri, rect, point, &pWorld->m_matProj, &g_Neuz.m_camera.m_matView, &vRayEnd, TRUE ); g_Neuz.m_vCursorPos = vRayEnd; if( g_Neuz.m_pCreateMonItem ) { if( bUp || bDown || bLeft || bRight || bSpace || m_bLButtonDown ) { BOOL bSendCM = TRUE; if( m_bLButtonDown ) { D3DXVECTOR3 vDist2 = g_pPlayer->GetPos() - g_Neuz.m_vCursorPos; float fDist = D3DXVec3Length( &vDist2 ); // 두좌표간의 거리 if( 15.f < fDist ) { g_WndMng.PutString( prj.GetText( TID_GAME_CREATEMON_F_15 ), NULL, prj.GetTextColor( TID_GAME_CREATEMON_F_15 ) ); bSendCM = FALSE; } if( bSendCM ) { int nAttr = g_pPlayer->GetWorld()->GetHeightAttribute( g_Neuz.m_vCursorPos.x, g_Neuz.m_vCursorPos.z ); // 이동할 위치의 속성 읽음. if( nAttr == HATTR_NOWALK || nAttr == HATTR_NOMOVE || g_pPlayer->IsRegionAttr( RA_SAFETY ) || g_pPlayer->GetWorld()->GetID() == WI_WORLD_GUILDWAR ) // 못 움직이는 곳이거나 안전지역이면 Pass { g_WndMng.PutString( prj.GetText( TID_GAME_CREATEMON_F_AREA ), NULL, prj.GetTextColor( TID_GAME_CREATEMON_F_AREA ) ); bSendCM = FALSE; } else if( g_pPlayer->GetWorld()->GetID() != WI_WORLD_MADRIGAL ) { g_WndMng.PutString( prj.GetText( TID_GAME_CREATEMON_F_AREA ), NULL, prj.GetTextColor( TID_GAME_CREATEMON_F_AREA ) ); bSendCM = FALSE; } if( bSendCM ) { g_DPlay.SendCreateMonster( MAKELONG( ITYPE_ITEM, g_Neuz.m_pCreateMonItem->m_dwObjId ), g_Neuz.m_vCursorPos ); } } m_bLButtonDown = FALSE; } if( bSendCM ) g_Neuz.m_pCreateMonItem = NULL; } } #endif // __ITEMCREATEMON_S0602 //TODO:ata3k님 꼭 고쳐주세요. 왜 그런지 아무도 몰라! // 이동금지 상태가 아닐때만 클릭으로 이동할수 있다. #ifdef __Y_INTERFACE_VER3 bool *bpButton; if( g_Option.m_nInterface == 2 ) bpButton = &m_bLButtonUp; else bpButton = &m_bLButtonDown; if( *bpButton ) #else //__Y_INTERFACE_VER3 if( m_bLButtonDown ) #endif //__Y_INTERFACE_VER3 { #ifdef __Y_INTERFACE_VER3 if( g_Option.m_nInterface == 2 ) { *bpButton = FALSE; if( m_timerLButtonDown.GetLeftTime() > 200 ) return nMsg; } #endif //__Y_INTERFACE_VER3 D3DXVECTOR3 vec3Tri[3]; if( pWorld->ClientPointToVector( vec3Tri, rect, point, &pWorld->m_matProj, &g_Neuz.m_camera.m_matView, &vRayEnd, TRUE ) ) { // 이동 포인트를 얻어 목표 세팅 if( m_bFreeMove ) { // if( m_bLButtonDown ) // 이동금지 상태가 아닐때만 클릭으로 이동할수 있다. { { if( m_pWndGuideSystem && m_pWndGuideSystem->IsVisible()) #if __VER >= 12 // __MOD_TUTORIAL m_pWndGuideSystem->m_Condition.bIsClickOnLand = true; #else m_pWndGuideSystem->SendGuideMessage(GUIDE_EVENT_MOVE); #endif #ifdef __IAOBJ0622 if( GetLastPickObj() && GetLastPickObj()->GetType() == OT_SHIP ) pMover->SetDestPos( (CShip *)GetLastPickObj(), vRayEnd ); else pMover->SetDestPos( vRayEnd ); #else pMover->SetDestPos( vRayEnd ); #endif pMover->m_nCorr = -1; #ifndef __J0823 m_bFreeMove = FALSE; g_DPlay.SendSnapshot( TRUE ); fCastCancel = true; if( g_pMoveMark && g_pMoveMark->m_pSfxObj ) g_pMoveMark->m_pSfxObj->m_nCurFrame = 180; CSfx *pObj = CreateSfx(g_Neuz.m_pd3dDevice,XI_GEN_MOVEMARK01,vRayEnd); D3DXVECTOR3 vVector1 = vec3Tri[2] - vec3Tri[0]; D3DXVECTOR3 vVector2 = vec3Tri[1] - vec3Tri[0]; D3DXVECTOR3 vNormal; D3DXVec3Cross( &vNormal, &vVector1, &vVector2); D3DXVec3Normalize( &vNormal, &vNormal ); D3DXVECTOR3 v3Up = D3DXVECTOR3( 0.0f, -1.0f, 0.0f ); D3DXVECTOR3 v3Cross; FLOAT fDot; FLOAT fTheta; D3DXVec3Cross( &v3Cross, &v3Up, &vNormal ); fDot = D3DXVec3Dot( &v3Up, &vNormal ); fTheta = acos( fDot ); D3DXQUATERNION qDirMap; D3DXQuaternionRotationAxis( &qDirMap, &v3Cross, fTheta ); D3DXVECTOR3 vYPW; QuaternionRotationToYPW( qDirMap, vYPW ); pObj->m_pSfxObj->m_vRotate.x = D3DXToDegree(vYPW.x); pObj->m_pSfxObj->m_vRotate.y = D3DXToDegree(vYPW.y); pObj->m_pSfxObj->m_vRotate.z = D3DXToDegree(vYPW.z); #endif // __J0823 m_objidTracking = NULL_ID; } } } } } //if( !pMover->IsEmptyDestPos() || !pMover->IsEmptyDestObj() ) // return nMsg; #ifdef __Y_INTERFACE_VER3 if( bUp || bDown || bLeft || bRight || bSpace || bLForward || bRForward ) // 이동 키조작이 들어가면 자동공격 멈춤. #else //__Y_INTERFACE_VER3 if( bUp || bDown || bLeft || bRight || bSpace ) // 이동 키조작이 들어가면 자동공격 멈춤. #endif //__Y_INTERFACE_VER3 { if( bUp || bDown ) #if __VER >= 12 // __MOD_TUTORIAL { CWndGuideSystem* pWndGuide = NULL; pWndGuide = (CWndGuideSystem*)GetWndBase( APP_GUIDE ); if(pWndGuide && pWndGuide->IsVisible()) pWndGuide->m_Condition.bIsKeyMove = true; } #else m_pWndGuideSystem->SendGuideMessage(GUIDE_EVENT_KEY_MOVE); #endif m_bAutoAttack = FALSE; g_pPlayer->ClearCmd(); if( !bSpace ) m_objidTracking = NULL_ID; } if( m_objidTracking != NULL_ID ) { CMover* pObjTracking = prj.GetMover( m_objidTracking ); if( pObjTracking ) { D3DXVECTOR3 vDis = pMover->GetPos() - pObjTracking->GetPos(); if( D3DXVec3LengthSq( &vDis ) > 16 ) pMover->SetDestObj( m_objidTracking ); } else m_objidTracking = NULL_ID; } bool fMoved = false; bool fBehavior = false; if( bUp ) { if( pMover->SendActMsg( OBJMSG_FORWARD ) == 1 ) { fMoved = true; fCastCancel = true; } } else if( bDown ) { if( pMover->SendActMsg( OBJMSG_BACKWARD ) == 1 ) { fMoved = true; fCastCancel = true; } } #ifdef __Y_INTERFACE_VER3 else if( bLForward ) { if( pMover->SendActMsg( OBJMSG_LFORWARD ) == 1 ) { fMoved = true; fCastCancel = true; } } else if( bRForward ) { if( pMover->SendActMsg( OBJMSG_RFORWARD ) == 1 ) { fMoved = true; fCastCancel = true; } } #endif //__Y_INTERFACE_VER3 else // if( (bUp == FALSE && s_bUped == TRUE) || (bDown == FALSE && s_bDowned == TRUE) ) // 키를 뗀 순간에만 처리해보자.. if( bUp == FALSE || bDown == FALSE ) { if( pMover->IsEmptyDest() ) { if( pMover->m_pActMover->IsActJump() == FALSE && (pMover->m_pActMover->IsStateFlag( OBJSTAF_SIT ) ) == 0 ) // 앉아있을땐 실행하면 안된다. { if( pMover->SendActMsg( OBJMSG_STAND ) == 1 ) { fMoved = true; // TRACE( "PlayerMoved, " ); } } } } // s_bUped = bUp; // s_bDowned = bDown; if( bLeft ) { if( pMover->SendActMsg( OBJMSG_LTURN ) == 1 ) { fMoved = true; } } else if( bRight ) { if( pMover->SendActMsg( OBJMSG_RTURN ) == 1 ) { fMoved = true; } } else { if( pMover->SendActMsg( OBJMSG_STOP_TURN ) == 1 ) { fMoved = true; // fBehavior = true; } } // jump if( bSpace ) { #if __VER < 12 // __MOD_TUTORIAL if( m_pWndGuideSystem ) m_pWndGuideSystem->SendGuideMessage(GUIDE_EVENT_KEY_JUMP); #endif if( pMover->SendActMsg( OBJMSG_JUMP ) == 1 ) { fBehavior = true; fCastCancel = true; } } if( m_bLButtonDown == TRUE && m_bRButtonDown == TRUE ) { if( m_timerLButtonDown.GetLeftTime() < 500 && m_timerRButtonDown.GetLeftTime() < 500 ) { if( g_pPlayer->SendActMsg( OBJMSG_JUMP ) == 1 ) { fBehavior = true; fCastCancel = true; } } } #ifdef __Y_INTERFACE_VER3 if( g_Option.m_nInterface == 2 ) { if( g_bKeyTable[VK_DIVIDE] || g_bKeyTable[191] ) { bWalk = TRUE; } else { bWalk = FALSE; } } else { bWalk = g_bKeyTable[g_Neuz.Key.chWalk]; } #else //__Y_INTERFACE_VER3 bWalk = g_bKeyTable[g_Neuz.Key.chWalk]; #endif //__Y_INTERFACE_VER3 if( bWalk && !s_bWalk2 ) // 걷기 모드 토글. { if( pMover->m_pActMover->IsStateFlag( OBJSTAF_WALK ) ) { if( pMover->SendActMsg( OBJMSG_MODE_RUN ) == 1 ) { g_WndMng.PutString( prj.GetText( TID_GAME_RUN ), NULL, prj.GetTextColor( TID_GAME_RUN ) , CHATSTY_SYSTEM_CLIENT ); fBehavior = true; } } else { #if __VER < 12 // __MOD_TUTORIAL if(m_pWndGuideSystem) m_pWndGuideSystem->SendGuideMessage(GUIDE_EVENT_KEY_RUN); #endif if( pMover->SendActMsg( OBJMSG_MODE_WALK ) == 1 ) { g_WndMng.PutString( prj.GetText( TID_GAME_WALK ), NULL, prj.GetTextColor( TID_GAME_WALK ) , CHATSTY_SYSTEM_CLIENT ); fBehavior = true; } } } s_bWalk2 = bWalk; if( fMoved || fBehavior ) { g_pPlayer->ClearDest(); #ifdef __J0823 g_DPlay.ClearPlayerDestPos(); #endif // __J0823 } if( fMoved ) g_DPlay.SendPlayerMoved(); if( fBehavior ) g_DPlay.SendPlayerBehavior(); if( g_pPlayer->IsStateMode( STATE_BASEMOTION_MODE ) && fCastCancel ) // 캐스트 취소 { g_DPlay.SendStateModeCancel( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_CANCEL ); } // 운영자가 쓰는 키. 서버로부터 좌표받아오기. if( bTempKey = g_bKeyTable[ '8' ] ) { if( !m_bTemp3ed ) { pMover->SendActMsg( OBJMSG_TEMP2 ); // __bTestLOD ^= 1; } } m_bTemp3ed = bTempKey; //----------- 스킬사용. /* static BOOL s_bShift2, s_bKeyC2; BOOL bShift, bKeyC; if( g_Option.m_nInterface == 1 ) // 신버전 인터페이스 방식은 X 가 스킬사용이다. { bShift = g_bKeyTable[ VK_SHIFT ]; bKeyC = g_bKeyTable[ 'C' ]; if( bKeyC ) { int a = 0; } if( (bShift && !s_bShift2) || (bKeyC && !s_bKeyC2) ) { CObj* pTargetObj = CObj::m_pObjHighlight; // 커서를 대고 있던 오브젝트가 하이라이트 오브젝이다. if( pTargetObj ) // 커서를 대고 있던 오브젝트가 있으면 { pWorld->SetObjFocus( pTargetObj ); // 그놈을 셀렉트 하는 동시에. CMover* pMover = (CMover*)pTargetObj; if( pMover->GetType() == OT_MOVER ) m_dwNextSkill = NEXTSKILL_ACTIONSLOT; // 스킬 사용 예약. } else m_dwNextSkill = NEXTSKILL_ACTIONSLOT; // 스킬 사용 예약. } s_bShift2 = bShift; s_bKeyC2 = bKeyC; } */ //------------ 비공정 타기 if( bBoard ) { if( !s_bBoarded ) // 플레이어가 비공정에 올라타있는 상태에서. 탑승키를 누르면. { if( g_pShip == NULL ) { if( g_pPlayer->GetIAObjLink() && g_pPlayer->GetIAObjLink()->GetType() == OT_SHIP && g_pPlayer->GetIAObjLink()->GetIndex() == 3 ) { CShip *pShip = (CShip *)g_pPlayer->GetIAObjLink(); if( pShip->GetMover() == NULL ) // 쥔장이 없는 배일때. { pShip->SetMover( g_pPlayer ); // 쥔장을 g_pPlayer로 설정. g_pShip = pShip; } } } else // 이미 배를 조종하고 있을때 { g_pShip->SetMover( NULL ); g_pShip = NULL; } } } s_bBoarded = bBoard; #ifdef _DEBUG // 디버깅용 키 if( bTempKey = g_bKeyTable[ VK_F2 ] ) { if( !s_bTempKeyed ) { // pMover->SendActMsg( OBJMSG_TEMP ); // g_Option.m_nObjectDetail ++; // if( g_Option.m_nObjectDetail > 2 ) g_Option.m_nObjectDetail = 0; } } s_bTempKeyed = bTempKey; if( bTempKey = g_bKeyTable[ 'F' ] ) { if( !m_bTemp2ed ) { pMover->SendActMsg( OBJMSG_TEMP3 ); } } m_bTemp2ed = bTempKey; #endif return nMsg; }
// 싸이킥 월 void CCommonCtrl::_ProcessWall( void ) { if( m_nCount == 0 ) { #ifdef __CLIENT m_pSfxModel = new CSfxModel; m_pSfxModel2 = new CSfxModel; m_pSfxModel->SetSfx( "sfx_sklpsypsychicwall02" ); m_pSfxModel2->SetSfx( "sfx_sklpsypsychicwall04" ); #endif } D3DXVECTOR3 vPos = GetPos(); #ifndef __CLIENT CObj* pObj; BOOL bApply; #endif //__CLIENT int nRange = 4; // 일반적으로 fDepth가 가장 길기때문에 검사 영역은 fDepth로 했다. float fDepth = 3; if( fDepth <= 4.0f ) nRange = 4; else if( fDepth <= 8.0f ) nRange = 8; else if( fDepth <= 16.0f ) nRange = 16; else nRange = 32; #ifdef __WORLDSERVER CMover *pAttacker = prj.GetMover( m_idAttacker ); if( IsInvalidObj( pAttacker ) ) // 일단 어태커가 사라지면 컨트롤도 사라지게 하자. { DestroyWall(); return; } int nMin = m_pAddSkillProp->dwAbilityMin + (pAttacker->GetLevel() + (pAttacker->GetInt() / 10) * (int)m_pAddSkillProp->dwSkillLvl); int nMax = m_pAddSkillProp->dwAbilityMax + (pAttacker->GetLevel() + (pAttacker->GetInt() / 10) * (int)m_pAddSkillProp->dwSkillLvl); int nDamage = xRandom( nMin, nMax ); #if __VER >= 9 // __SKILL_0706 int nMinPVP = m_pAddSkillProp->dwAbilityMinPVP + ( pAttacker->GetLevel() + ( pAttacker->GetInt() / 10 ) * (int)m_pAddSkillProp->dwSkillLvl ); int nMaxPVP = m_pAddSkillProp->dwAbilityMaxPVP + ( pAttacker->GetLevel() + ( pAttacker->GetInt() / 10 ) * (int)m_pAddSkillProp->dwSkillLvl ); int nDamagePVP = xRandom( nMinPVP, nMaxPVP ); #endif // __SKILL_0706 int nHitPoint = 0; int nTargetHP = 0; FOR_LINKMAP( GetWorld(), vPos, pObj, nRange, CObj::linkDynamic, GetLayer() ) { bApply = FALSE; if( pObj->GetType() == OT_MOVER ) // 대상이 무버일때만. { CMover *pTarget = (CMover *)pObj; if( pTarget->IsPeaceful() == FALSE ) // NPC가 아닌경우만 적용 bApply = TRUE; #if __VER >= 8 // #ifdef __JHMA_VER_8_5_1 // 8.5차 경비병 범위스킬 공격효과 불가로 수정 World if( pAttacker->IsPlayer() && pAttacker->IsChaotic() == FALSE && pTarget->GetProp()->dwClass == RANK_GUARD ) bApply = FALSE; #endif // #endif // __JHMA_VER_8_5_1 // 8.5차 경비병 범위스킬 공격효과 불가로 수정 World if( bApply ) { if( IsValidObj( pTarget ) && pTarget->IsLive() ) { if( pObj->IsRangeObj( vPos, 1.0f ) ) { if( IsValidObj(pAttacker) ) { nTargetHP = pTarget->GetHitPoint(); nHitPoint = nTargetHP - nDamage; if( nHitPoint > 0 ) { pTarget->m_nHitPoint = nHitPoint; g_UserMng.AddDamage( pTarget, pAttacker->GetId(), nDamage, AF_GENERIC ); } else { pAttacker->SubExperience( pTarget ); // pTarget를 죽이고 난후의 m_pAttacker 경험치 처리. pTarget->DropItemByDied( pAttacker ); // 몬스터였다면 아이템 드랍. pAttacker->m_nAtkCnt = 0; // 타겟을 죽였으면 공격자의 어택카운트 클리어 pTarget->DoDie( pAttacker ); // pTarget 죽어라. pTarget->m_nHitPoint = 0; } } m_nLife ++; // 부딪힐때마다 카운트 올라감 if( m_nLife >= (int)(m_pAddSkillProp->dwSkillLvl / 2) ) DestroyWall(); // 뒤로 밀리기 처리. #if __VER >= 10 // __AI_0711 if( pTarget->IsRank( RANK_MIDBOSS ) == FALSE ) #endif // __AI_0711 { FLOAT fPushAngle = pTarget->GetAngle() + 180.0f; FLOAT fPower = 0.825f; AngleToVectorXZ( &pTarget->m_pActMover->m_vDeltaE, fPushAngle, fPower ); g_UserMng.AddPushPower( pTarget, pTarget->GetPos(), pTarget->GetAngle(), fPushAngle, fPower ); } } } } } }
void CActionMover::ProcessFlyMove( void ) { #ifdef __CLIENT g_nDrift = 0; // 드리프트 플랙 클리어 #endif float fLenSq = D3DXVec3LengthSq( &m_vDelta ); if( fLenSq == 0.0f && (GetStateFlag() & OBJSTAF_ACC ) == 0 ) return; // 멈춤 상태면 리턴 CMover* pMover = m_pMover; FLOAT fAccPwr = m_fAccPower; #ifdef __CLIENT ProcessFlyTracking(); #endif // client // 터보모드 처리 if( (GetStateFlag() & OBJSTAF_TURBO) && (GetStateFlag() & OBJSTAF_ACC) ) // 터보모드 & 전진중 { #ifdef __WORLDSERVER pMover->m_tmAccFuel = (int)( pMover->m_tmAccFuel - (1000.0f / (float)FRAME_PER_SEC) ); // 1/60만큼 깎음 #endif if( pMover->m_tmAccFuel <= 0 ) // 가속연료가 다 떨어지면 { pMover->m_tmAccFuel = 0; SendActMsg( OBJMSG_MODE_TURBO_OFF ); // 터보모드 중지 #ifdef __WORLDSERVER g_UserMng.AddSendActMsg( pMover, OBJMSG_MODE_TURBO_OFF ); #endif } else fAccPwr *= 1.2f; // 가속연료가 남아있다면 터보모드 } #ifdef __CLIENT ProcessFlyParticle( fLenSq ); #endif // 관성처리 if( fAccPwr > 0.0f ) { // 힘벡터 생성 FLOAT fAngX = D3DXToRadian( pMover->GetAngleX() ); FLOAT fAng = D3DXToRadian( pMover->GetAngle() ); FLOAT fDist = cosf(fAngX) * fAccPwr; D3DXVECTOR3 vAcc; vAcc.x = sinf( fAng ) * fDist; vAcc.z = -cosf( fAng ) * fDist; vAcc.y = -sinf( fAngX ) * fAccPwr; // 관성벡터와 추진력벡터가 각도가 50도 이하면 급추진 if( fLenSq > 0.01f ) { D3DXVECTOR3 vDeltaNorm, vAccNorm; D3DXVec3Normalize( &vDeltaNorm, &m_vDelta ); D3DXVec3Normalize( &vAccNorm, &vAcc ); float fDot = D3DXVec3Dot( &vDeltaNorm, &vAccNorm ); if( fDot < 0.633319f ) // 이전코드: cosf(70.0f) 값으로는 대략 50도 { vAcc *= 2.0f; m_vDelta *= 0.985f; #ifdef __CLIENT g_nDrift = 1; if( ! ( pMover->IsMode( TRANSPARENT_MODE ) ) ) // 투명상태가 아닐때만 렌더. { if( (g_nProcessCnt & 3) == 0 ) CreateSfx( g_Neuz.m_pd3dDevice, XI_NAT_DUST_RUN, pMover->GetPos() ); } #endif } } fLenSq = D3DXVec3LengthSq( &m_vDelta ); // 1/60 sec 속도 float fMaxSpeed = 0.3f; if( GetStateFlag() & OBJSTAF_TURBO ) // 터보모드에선 MAX속도가 1.1배 fMaxSpeed *= 1.1f; if( fLenSq < (fMaxSpeed * fMaxSpeed) ) // 일정이상 속도를 넘지 않게 하자. m_vDelta += vAcc; // 관성벡터 += 추진력벡터 } m_vDelta *= (1.0f - FRIC_AIR); // 마찰력에 의한 감소 // raiders - 수치적 안정성을 위해서 적은 수치가 계산되는 것을 피한다. fLenSq = D3DXVec3LengthSq( &m_vDelta ); if( m_fAccPower == 0.0f && fLenSq < 0.0002f * 0.0002f ) { fLenSq = 0; m_vDelta = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); RemoveStateFlag( OBJSTAF_ACC ); // 가속상태 해제 } #ifdef __CLIENT if( pMover->IsActiveMover() ) { g_nFlySpeed = (int)( (sqrt(fLenSq) * 60.0f) * 60.0f * 60.0f ); g_nFlySpeed = (int)( g_nFlySpeed / 200.0f ); } #endif }
void CSfx::Process() { #ifdef _DEBUG if( m_dwIndex == XI_SKILL_MAG_FIRE_HOTAIR01 ) // 디버깅 하려면 이걸 바꿔 쓰세요. { int a = 0; } #endif m_nFrame++; if( m_nSec == 0 ) // 0은 1회 플레이후 종료. { if( m_pSfxObj->Process() ) // return true는 애니메이션 끝. Delete(); } else { // 반복 애니메이션 if( m_pSfxObj->Process() ) m_pSfxObj->m_nCurFrame = 0; if( m_nSec != -1 ) // 무한반복(-1)이 아니면 { if( m_nFrame > ( m_nSec * 60 ) ) // 시간 체크를 한다. Delete(); } } #ifdef __CLIENT if(m_pSfxObj->m_pSfxBase != NULL) { for( int j=0; j<m_pSfxObj->m_pSfxBase->m_apParts.GetSize(); j++ ) { if( m_pSfxObj->m_pSfxBase->Part(j)->m_nType != SFXPARTTYPE_MESH ) continue; CModelObject* pMesh = NULL; pMesh = g_SfxMeshMng.Mesh( m_pSfxObj->m_pSfxBase->Part(j)->m_strTex ); if( pMesh ) pMesh->FrameMove(); } } #endif //__CLIENT if( m_idDest != NULL_ID ) // Dest가 지정되어 있을때. { CMover* pObjDest = (CMover*)prj.GetCtrl( m_idDest ); if( IsValidObj( pObjDest ) ) // 유효한넘인가? m_vPosDest = pObjDest->GetPos(); // 당시 좌표를 계속 받아둠. Invalid상태가 되면 마지막 좌표로 세팅된다. SetPos( m_vPosDest ); // 타겟에 오브젝트 발동. #ifdef __CLIENT #if __VER >= 11 // __MA_VER11_06 // 확율스킬 효과수정 world,neuz if( m_dwIndex == XI_SKILL_PSY_HERO_STONE02 ) { if( IsValidObj( pObjDest ) ) // 유효한넘인가? { DWORD dwTmpID = pObjDest->GetRemoveSfxObj(XI_SKILL_PSY_HERO_STONE02 ); if( dwTmpID && m_nFrame > 0) { Delete(); return; } } } #endif // __MA_VER11_06 // 확율스킬 효과수정 world,neuz // 091022 mirchang - 프로텍션, 펜바리어 스킬 버프 해제 시 sfx 삭제 if( m_dwIndex == XI_SKILL_MER_SHIELD_PANBARRIER02 ) { if( IsValidObj( pObjDest ) ) // 유효한넘인가? { DWORD dwTmpID = pObjDest->GetRemoveSfxObj( XI_SKILL_MER_SHIELD_PANBARRIER02 ); if( dwTmpID && m_nFrame > 0) { Delete(); return; } } } if( m_dwIndex == XI_SKILL_MER_SHIELD_PROTECTION02 ) { if( IsValidObj( pObjDest ) ) // 유효한넘인가? { DWORD dwTmpID = pObjDest->GetRemoveSfxObj( XI_SKILL_MER_SHIELD_PROTECTION02 ); if( dwTmpID && m_nFrame > 0) { Delete(); return; } } } #endif // __CLIENT } else { // Dest가 지정되어 있지 않을때. Src로... if( m_idSrc != NULL_ID ) { CMover* pObjSrc = (CMover*)prj.GetCtrl( m_idSrc ); if( IsValidObj( pObjSrc ) ) // 소스아이디가 지정되어 있으면 SetPos( pObjSrc->GetPos() ); // 소스측에 이펙 발동. else Delete(); } } }
void CActionMover::ProcessFlyParticle( float fLenSq ) { CMover *pMover = m_pMover; // 운영자 투명모드때는 파티클 안나옴. if( (pMover->IsMode( TRANSPARENT_MODE ) ) == 0 ) { ItemProp* pRideProp = prj.GetItemProp( m_pMover->m_dwRideItemIdx ); // 현재 타고있는 탈것의 프로퍼티. // 비행 파티클 처리. if( fLenSq > 0.01f ) { if( (pMover->IsActiveMover() && g_Neuz.m_camera.m_fZoom > 2.0f) || pMover->IsActiveMover() == FALSE ) // 일정속도 이상이 되면 꼬리에 파티클이 나오기 시작. { int nType = 0; if( pRideProp && pRideProp->dwID == II_RID_RID_BOR_RIDINGCLOUD ) nType = 1; CreateFlyParticle( pMover, pMover->GetAngleX(), nType ); } } if( fLenSq > 0.001f ) { if( (pMover->IsActiveMover() && g_Neuz.m_camera.m_fZoom > 1.0f) || pMover->IsActiveMover() == FALSE ) { if( pRideProp && pRideProp->dwItemKind3 == IK3_BOARD ) // 보드만 꼬리가 나온다. { if( m_pTail ) { if( pRideProp->dwID == II_RID_RID_BOR_RIDINGCLOUD ) // 근두운일때 { if( m_pTail->GetType() != 2 ) // 생성되었던 꼬리고 근두운용이 아니면 m_pTail->ChangeTexture( D3DDEVICE, "etc_Tail2.bmp", 2 ); } else { if( m_pTail->GetType() != 1 ) // 생성되었던 꼬리고 일반보드용이 아니면 m_pTail->ChangeTexture( D3DDEVICE, "etc_Tail1.bmp", 1 ); // 일반보드용으로 텍스쳐 교체. } } if( m_pTail == NULL ) // 아직 할당 안됐으면 할당하고. { if( pRideProp->dwID == II_RID_RID_BOR_RIDINGCLOUD ) // 근두운... { m_pTail = (CTailEffectBelt*)g_TailEffectMng.AddEffect( g_Neuz.m_pd3dDevice, "etc_Tail2.bmp", 2 ); } else { m_pTail = (CTailEffectBelt*)g_TailEffectMng.AddEffect( g_Neuz.m_pd3dDevice, "etc_Tail1.bmp", 1 ); } } D3DXVECTOR3 vPos1, vPos2; D3DXVECTOR3 vLocal; FLOAT fAngXZ = pMover->GetAngle(); FLOAT fAngH = pMover->GetAngleX(); AngleToVectorXZ( &vLocal, fAngXZ, -1.0f ); fAngXZ -= 90.0f; if( fAngXZ < 0 ) fAngXZ += 360.0f; AngleToVector( &vPos1, fAngXZ, -fAngH, 0.5f ); vPos1 += pMover->GetPos(); vPos1 += vLocal; fAngXZ = pMover->GetAngle(); fAngH = pMover->GetAngleX(); AngleToVectorXZ( &vLocal, fAngXZ, -1.0f ); fAngXZ += 90.0f; if( fAngXZ > 360.0f ) fAngXZ -= 360.0f; AngleToVector( &vPos2, fAngXZ, -fAngH, 0.5f ); vPos2 += pMover->GetPos(); vPos2 += vLocal; if( m_pTail ) m_pTail->CreateTail( vPos1, vPos2 ); } } } } // 투명모드가 아닐때 }
void CBackCamera::Process( LPDIRECT3DDEVICE9 pd3dDevice ,float fFactor ) { #ifdef __CLIENT CMover *pMover = CMover::GetActiveMover(); // 여기서 카메라 세팅!!!!! if( pMover == NULL ) return; CWorld* pWorld = pMover->GetWorld(); if( pWorld == NULL ) return; D3DXMATRIX matView, mat; FLOAT fAngle = 0, fAngleY = 0; D3DXVECTOR3 vPos = pMover->GetPos(); vPos.y += 0.9f; #if __VER >= 13 // __HOUSING if(m_nCamMode == CM_MYROOM) { if(m_fZoom <= 0.5f) m_fZoom = 0.5f; // if(m_fZoom >= 3.0f) m_fZoom = 3.0f; } #endif // __HOUSING CMover* pMoverTarget = (CMover*)g_WorldMng.Get()->GetObjFocus() ; D3DXVECTOR3 vTarget,vTemp; if( pMoverTarget && pMover->m_pActMover->IsFly() && (pMover->m_dwFlag & MVRF_TRACKING) ) { // 날고 있는 경우 타겟이 있다면 // 타겟쪽으로 카메라 방향을 수정한다. vTemp = vPos - pMoverTarget->GetPos(); if( vTemp.z > 0 ) { fAngle =- (float)( atan( vTemp.x / vTemp.z ) * 180 / 3.1415926f ); } else { fAngle =- (float)( atan( vTemp.x / vTemp.z ) * 180 / 3.1415926f ) + 180; } D3DXVECTOR3 vDistXZ = vTemp; vDistXZ.y = 0; float fDistSq = D3DXVec3Length( &vDistXZ ); // XZ평면에서의 길이 fAngleY = atan2( fDistSq, vTemp.y/* * vTemp.y*/ ); fAngleY = D3DXToDegree( fAngleY ); float fReg1 = vTemp.y / 40.0f; if( fReg1 > 0 ) { if( fReg1 >= 2.0f ) fReg1 = 2.0f; } else if( fReg1 < 0 ) { if( fReg1 <= -2.0f ) fReg1 = -2.0f; } m_fCurRoty = m_fRoty + m_fZoom * fReg1; if( m_bLock ) fAngle = 0; } else { fAngle = pMover->GetAngle(); if( m_bLock ) fAngle = 0; fAngleY = 90.0f; m_fCurRoty = m_fRoty + m_fZoom * 4; } m_vLookAt = vPos; #ifdef __Y_CAMERA_SLOW_8 if( !g_WndMng.m_pWndWorld->m_bRButtonDown && ( !g_bKeyTable[ VK_LEFT ] && !g_bKeyTable[ VK_RIGHT ] ) ) { static FLOAT fSpeed = 2.0f; BOOL bLeft = FALSE; BOOL bRight = FALSE; FLOAT fTemp = 0.0f; fTemp = m_fRotx; if( (GetAnglePie(fTemp) == 1 && GetAnglePie(m_fCurRotx) == 4) ) bRight = TRUE; if( (GetAnglePie(fTemp) == 4 && GetAnglePie(m_fCurRotx) == 1) ) bLeft = TRUE; if( bRight ) { m_fCurRotx += m_fRotx; if( m_fCurRotx < fTemp ) { m_fCurRotx += fSpeed; } m_fCurRotx -= m_fRotx; if( m_fCurRotx >= 0.0f ) { m_fCurRotx = -360.0f; } } if( bLeft ) { fTemp += -360.0f; if( m_fCurRotx > fTemp ) { m_fCurRotx += -fSpeed; if( m_fCurRotx < -360.0f ) m_fCurRotx = 0.0f; } fTemp -= -360.0f; } if( !bLeft && !bRight ) { FLOAT fGoal = fabs(m_fCurRotx - fTemp); if( m_fCurRotx < fTemp ) { if( fGoal > fSpeed ) m_fCurRotx += fSpeed; } else { if( fGoal > fSpeed ) m_fCurRotx -= fSpeed; } } } else { m_fCurRotx = m_fRotx; } #else //__Y_CAMERA_SLOW_8 m_fCurRotx = m_fRotx; #endif //__Y_CAMERA_SLOW_8 #ifdef __XUZHU _g_fReg[0] = fAngleY; #endif float fAdjAng = (1.0f - fAngleY / 90.0f) * 45.0f; m_fCurRoty += fAdjAng; m_fCurRoty += pMover->GetAngleX(); if( pMover->m_pActMover->IsFly() ) // 비행할땐 조금 들어주자 m_fCurRoty += 0.0f; if( m_fCurRoty > 80.0f ) m_fCurRoty = 80.0f; #if __VER >= 13 // __HOUSING if(m_nCamMode == CM_MYROOM) { if(m_fCurRoty <= 10.0f) { m_fCurRoty = 10.0f; if(m_fRoty > 0.0f) m_fRoty = 0.0f; if(m_fRoty < -30.0f) m_fRoty = -30.0f; } } #endif // __HOUSING fAngle = m_fCurRotx - fAngle + 180.0f; D3DXMATRIX matTemp; // zoom 상태에 따라 카메라 위치를 조정 extern float fDiv; if( fDiv == 2.0f ) //vTemp = D3DXVECTOR3( 0.0f, 0.0f, -0.0f - (m_fZoom / 2.0f) * 2.0f ); vTemp = D3DXVECTOR3( 0.0f, 0.0f, -0.0f - 2.0f ); else { if( g_pShip ) vTemp = D3DXVECTOR3( 0.0f, 0.0f, -4.0f - m_fZoom * 16.0f ); else //vTemp = D3DXVECTOR3( 0.0f, 0.0f, -50.0f ); vTemp = D3DXVECTOR3( 0.0f, 0.0f, -4.0f - m_fZoom * 2.0f ); } D3DXVECTOR3 vecOut; D3DXMatrixRotationX( &matTemp, D3DXToRadian( m_fCurRoty / 1.0f ) ); D3DXVec3TransformCoord( &vTemp, &vTemp, &matTemp ); D3DXMatrixRotationY( &matTemp, D3DXToRadian( fAngle ) ); D3DXVec3TransformCoord( &m_vOffsetDest, &vTemp, &matTemp ); D3DXVECTOR3 vecOffsetDelta = ( ( m_vOffsetDest - m_vOffset ) + m_vPosVal ) / fFactor; m_vOffset += vecOffsetDelta; m_vPosVal /= 2; m_vPos = vPos + m_vOffset; BOOL bCrash; FLOAT fLength; static D3DXVECTOR3 m_vLimitPos; D3DXVECTOR3 m_vOutPos = m_vPos; m_vLookAt.y += 0.4f; #if __VER >= 11 // __GUILD_COMBAT_1TO1 if( g_pPlayer && g_GuildCombat1to1Mng.IsPossibleMover( g_pPlayer ) ) bCrash = FALSE; else bCrash = pWorld->CheckBound( &m_vPos, &m_vLookAt, &m_vOutPos, &fLength ); #else //__GUILD_COMBAT_1TO1 bCrash = pWorld->CheckBound( &m_vPos, &m_vLookAt, &m_vOutPos, &fLength ); #endif //__GUILD_COMBAT_1TO1 // 충돌이있다면 마지막으로 충돌했던 거리를 저장 if( bCrash ) m_fLength2 = fLength; // 전프레임에 충돌, 현재는 충돌이 아닐때...즉, 서서히 뒤로 가게하는 시점.. if( m_bOld && bCrash == FALSE ) { m_fLength1 = fLength; m_bStart = TRUE; } if( m_bStart ) { D3DXVECTOR3 vCPos = vPos + m_vOffset; D3DXVECTOR3 vDir = vCPos - m_vLookAt; D3DXVec3Normalize(&vDir, &vDir); #if __VER >= 12 // __CAM_FAST_RECOVER m_fLength2 += 0.37f; #else m_fLength2 += 0.07f; #endif if( m_fLength2 > fLength ) m_bStart = FALSE; m_vOutPos = m_vLookAt + (vDir * m_fLength2); } else if( bCrash ) {/* if( fLength < 5.0f ) { D3DXVECTOR3 vCPos = vPos + m_vOffset; D3DXVECTOR3 vDir = vCPos - m_vLookAt; D3DXVec3Normalize(&vDir, &vDir); FLOAT fff = m_vOutPos.y; m_vOutPos = m_vLookAt + (vDir * 5.0f); m_vOutPos.y = fff; } */ } m_bOld = bCrash; g_ModelGlobal.SetCamera( m_vOutPos, m_vLookAt ); m_vPos = m_vOutPos; #endif // CLIENT }
BOOL CAIMonster2::BeginAttack() { CMover *pMover = GetMover(); OBJMSG dwMsg = OBJMSG_NONE; DWORD dwItemID = 0; MoverProp *pProp = pMover->GetProp(); // 추격하여 도착하면 선택되었던 공격방식을 적용시킨다. switch( m_nAttackType ) { case CAT_NORMAL: dwMsg = OBJMSG_ATK1; dwItemID = pProp->dwAtk1; break; case CAT_NORMAL2: dwMsg = OBJMSG_ATK2; dwItemID = pProp->dwAtk1; break; case CAT_QUAKEDOUBLE: dwMsg = OBJMSG_ATK3; dwItemID = pProp->dwAtk3; break; case CAT_QUAKE_ONE: dwMsg = OBJMSG_ATK4; dwItemID = pProp->dwAtk2; break; default: ASSERT(0); } if( dwMsg == OBJMSG_NONE ) return FALSE; if( m_idTarget == NULL_ID ) return FALSE; // LPMODELELEM lpModelElem = prj.m_modelMng.GetModelElem( OT_MOVER, pMover->GetIndex() ); // if( lpModelElem == NULL ) // return FALSE; // if( lpModelElem->m_nMax dwMsg = OBJMSG_ATK1; int nResult = pMover->DoAttackMelee( m_idTarget, dwMsg, dwItemID ); if( nResult ) { CMover *pTarget = prj.GetMover( m_idTarget ); // 이벤트 메세지 // 보스몬스터가 유저에게 말을 한다. switch( m_nAttackType ) { case CAT_QUAKEDOUBLE: { if( pTarget ) { g_UserMng.AddWorldShout( pMover->GetName(), prj.GetText(TID_GAME_BOSS_BIGMUSCLE_MSG_04), pTarget->GetPos(), pTarget->GetWorld() ); } } break; case CAT_QUAKE_ONE: { if( pTarget ) { TCHAR szChar[128] = { 0 }; sprintf( szChar, prj.GetText(TID_GAME_BOSS_BIGMUSCLE_MSG_05), pTarget->GetName() ); g_UserMng.AddWorldShout( pMover->GetName(), szChar, pTarget->GetPos(), pTarget->GetWorld() ); } } break; } return TRUE; } return FALSE; }
// 공격 대상을 찾아서 m_idTarget에 세팅한다. BOOL CAIMonster2::Search() { CMover *pMover = GetMover(); CWorld *pWorld = GetWorld(); CModelObject *pModel = (CModelObject *)pMover->GetModel(); FLOAT fRadius = pMover->GetRadiusXZ(); // this의 반지름 FLOAT fRadiusSq = fRadius * fRadius; // 반지름Sq버전. if( m_idTarget == NULL_ID && // 공격대상이 정해지지 않았고 (m_vTarget.x == 0 && m_vTarget.y == 0 && m_vTarget.z == 0) ) // 공격위치도 정해지지 않았다. { // 어떤 쉐리를 공격할까....? 를 선정함. if( SelectTarget() == FALSE ) return FALSE; } D3DXVECTOR3 vTarget; FLOAT fDistSq = 0; // 공격지점과 this의 거리. CMover *pTarget = NULL; if( m_idTarget != NULL_ID ) // 타겟오브젝이 있을때 { pTarget = prj.GetMover( m_idTarget ); if( IsValidObj(pTarget) ) vTarget = pTarget->GetPos(); // 공격좌표는 타겟무버의 좌표 else { m_idTarget = NULL_ID; return FALSE; // 타겟이 거시기 하면 걍리턴. } } else if( m_vTarget.x && m_vTarget.y && m_vTarget.z ) // 공격 좌표로 설정되어 있을때. { vTarget = m_vTarget; } else { return FALSE; // 타겟이 거시기 하면 걍리턴. } D3DXVECTOR3 vDist = vTarget - pMover->GetPos(); fDistSq = D3DXVec3LengthSq( &vDist ); // 목표지점까지는 거리. m_fAttackRange = fRadius; // 얼마나 근접해야하는가? 디폴트로 반지름 길이. if( fDistSq < fRadiusSq * 4.0f ) // 근거리면. { DWORD dwNum = xRandom( 100 ); // 0 ~ 99까지으 난수. if( dwNum < 85 ) { if( xRandom( 2 ) ) m_nAttackType = CAT_NORMAL; // 앞발로 밟기. else m_nAttackType = CAT_NORMAL2; m_fAttackRange = 5.0f; // 딱붙어서 밟아야 한다. ?? } else { m_nAttackType = CAT_QUAKEDOUBLE; // 두손으로 내려치기 - 스턴 } } else if( fDistSq < fRadiusSq * 6.0f ) // 반지름의 x배 이하는 쏘기. { DWORD dwNum = xRandom( 100 ); // 0 ~ 99까지으 난수. // 반지름 3배거리 이상이면 원거리. if( dwNum < 60 ) { m_nAttackType = CAT_QUAKE_ONE; // 하늘에서 돌 떨어뜨리기 m_fAttackRange = 15.0f; // xx미터 까지 접근하자. ?? } else { m_idTarget = NULL_ID; return FALSE; } } else { m_nAttackType = CAT_NORMAL; // 앞발로 밟기. m_fAttackRange = fRadius; //10.0f; } return TRUE; }
BOOL CAIMonster2::SelectTarget() { CMover *pMover = GetMover(); CWorld *pWorld = GetWorld(); int nAttackFirstRange = pMover->GetProp()->m_nAttackFirstRange; FLOAT fRadius = pMover->GetRadiusXZ(); // this의 반지름 FLOAT fRadiusSq = fRadius * fRadius; // 반지름Sq버전. CMover *pLastAttacker = prj.GetMover( m_idLastAttacker ); if( IsValidObj( pLastAttacker ) && pLastAttacker->IsDie() ) { m_idLastAttacker = NULL_ID; pLastAttacker = NULL; } if( pLastAttacker == NULL ) // LastAttacker가 없어졌으면 타겟 다시 잡을 수 있도록 하자. { m_idLastAttacker = NULL_ID; } else { D3DXVECTOR3 vDist = pLastAttacker->GetPos() - pMover->GetPos(); FLOAT fDistSq = D3DXVec3LengthSq( &vDist ); // 목표지점까지의 거리. if( fDistSq >= fRadiusSq * 10.0f ) // 라스트어태커가 내 반지름의 10배이상 떨어져있으면 { // 타겟 포기 m_idLastAttacker = NULL_ID; pLastAttacker = NULL; } } m_idTarget = NULL_ID; m_vTarget.x = m_vTarget.y = m_vTarget.z = 0; // 일단 이건 안쓰는걸로 하자. if( m_idLastAttacker == NULL_ID ) // 아직 날 때린쉐리가 없다. { CMover* pTarget = NULL; pTarget = ScanTarget( pMover, nAttackFirstRange, JOB_ALL ); if( pTarget ) { if( pMover->IsFlyingNPC() == pTarget->m_pActMover->IsFly() ) // 위상이 같으면 OK m_idTarget = pTarget->GetId(); else return FALSE; } else return FALSE; } else { // 날 때린 쉐리가 있다. DWORD dwNum = xRandom( 100 ); // 0 ~ 99까지으 난수. DWORD dwAggroRate = 50; if( IsValidObj( pLastAttacker ) ) { if( pLastAttacker->GetJob() == JOB_MERCENARY ) // 마지막으로 날때린 쉐리가 머서면 어그로 좀더 주자. dwAggroRate = 70; } if( dwNum < dwAggroRate ) { // dwAggroRate% 확률로 마지막으로 날 때린넘 공격. m_idTarget = m_idLastAttacker; // 날 공격한 쉐리를 타겟으로 지정하자. } else if( dwNum < 75 ) { // 50미터 반경내에서 가장 쎈넘을 잡자. CMover *pTarget = ScanTargetStrong( pMover, (float)( nAttackFirstRange ) ); if( pTarget ) { // this가 비행형 몬스터거나 || 타겟이 비행중이 아닐때만 공격. if( pMover->IsFlyingNPC() == pTarget->m_pActMover->IsFly() ) m_idTarget = pTarget->GetId(); else m_idTarget = m_idLastAttacker; // 타겟이 공격하기가 여의치 않으면 마지막으로 때린쉐리 공격하자. } else m_idTarget = m_idLastAttacker; // 타겟이 공격하기가 여의치 않으면 마지막으로 때린쉐리 공격하자. } else if( dwNum < 100 ) { // 오버힐하는 어시를 죽이자. CMover *pTarget = ScanTargetOverHealer( pMover, (float)( nAttackFirstRange ) ); if( pTarget ) { // this가 비행형 몬스터거나 || 타겟이 비행중이 아닐때만 공격. if( pMover->IsFlyingNPC() == pTarget->m_pActMover->IsFly() ) m_idTarget = pTarget->GetId(); else m_idTarget = m_idLastAttacker; // 타겟이 공격하기가 여의치 않으면 마지막으로 때린쉐리 공격하자. } else m_idTarget = m_idLastAttacker; // 타겟이 공격하기가 여의치 않으면 마지막으로 때린쉐리 공격하자. } } return TRUE; }
int CWndWorld::ControlFlying( DWORD dwMessage, CPoint point ) { static float fTurnAngle = 0.0f; static BOOL s_bTraceKeyed = 0, s_bSelectKeyed = 0, s_bTurbo2 = 0; // static BOOL s_bFastTurn; int nMsg = 0; // BOOL bFlyKey; BOOL bUp, bDown, bLeft, bRight; BOOL bAcc = FALSE; BOOL bTurbo; // BOOL bFastTurn = FALSE; BYTE nFrame = MAX_CORR_SIZE_150; CMover* pMover = CMover::GetActiveMover(); bUp = g_bKeyTable[g_Neuz.Key.chUp]; bDown = g_bKeyTable['S']; // 좌/우 회전 bLeft = g_bKeyTable[g_Neuz.Key.chLeft]; bRight = g_bKeyTable['D']; // 급선회. // bFastTurn = g_bKeyTable[ VK_SHIFT ]; // CMover* pMoverTarget = (CMover*)g_WorldMng.Get()->GetObjFocus() ; // 가속 상태면 전진 명령 계속 보냄 bool fMoved = false; bool fBehavior = false; if( pMover->m_pActMover->IsStateFlag( OBJSTAF_ACC ) ) { if( pMover->SendActMsg( OBJMSG_FORWARD ) == 1 ) { fMoved = true; } } else { if( pMover->SendActMsg( OBJMSG_STAND ) == 1 ) { fMoved = true; } } // bAcc = g_bKeyTable[VK_SPACE]; if( bAcc && !s_bAccKeyed ) // 키 누른순간에만 토글시킴. { if( pMover->m_pActMover->IsStateFlag( OBJSTAF_ACC ) ) // 가속중이었다면 { pMover->SendActMsg( OBJMSG_ACC_STOP ); // 가속 멈춤 if( pMover->m_pActMover->IsActTurn() ) { fMoved = true; } } else { // 가속중이 아니었다면 가속 시킴. if( pMover->SendActMsg( OBJMSG_ACC_START ) == 0 ) g_WndMng.PutString( prj.GetText( TID_GAME_AIRFUELEMPTY ) ); else { if( pMover->SendActMsg( OBJMSG_FORWARD ) == 1 ) fMoved = true; } } } s_bAccKeyed = bAcc; bTurbo = g_bKeyTable[g_Neuz.Key.chWalk]; if( bTurbo && !s_bTurbo2 ) // 토글 방식. { if( pMover->m_pActMover->IsStateFlag( OBJSTAF_TURBO ) ) { if( pMover->SendActMsg( OBJMSG_MODE_TURBO_OFF ) == 1 ) fMoved = true; } else { if( pMover->SendActMsg( OBJMSG_MODE_TURBO_ON ) == 1 ) fMoved = true; } } s_bTurbo2 = bTurbo; if( pMover->m_pActMover->IsFly() ) { if( g_bKeyTable[g_Neuz.Key.chTrace] && !s_bTraceKeyed ) { CCtrl* pFocusObj = (CCtrl*)(pMover->GetWorld()->GetObjFocus()); if( pFocusObj && pFocusObj->GetType() == OT_MOVER ) { CMover* pFocusMover = (CMover*)pFocusObj; if( pMover->m_dwFlag & MVRF_TRACKING ) // 이미 실행중이면 해제. { pMover->m_dwFlag &= (~MVRF_TRACKING); // 추적모드해제. pMover->m_idTracking = NULL_ID; } else { // 비행중 추적모드. pMover->m_dwFlag |= MVRF_TRACKING; // 추적모드. pMover->m_idTracking = pFocusMover->GetId(); } } else { // 타겟이 없을때 Z키를 누르면 자동추적이 풀린다. pMover->m_dwFlag &= (~MVRF_TRACKING); // 추적모드해제. pMover->m_idTracking = NULL_ID; } } s_bTraceKeyed = g_bKeyTable[g_Neuz.Key.chTrace]; // 타겟선택 키 if( g_bKeyTable[VK_TAB] && !s_bSelectKeyed ) { if( m_aFlyTarget.GetSize() > 0 ) // 선택된 타겟있을때. { if( m_nSelect >= m_aFlyTarget.GetSize() ) m_nSelect = 0; OBJID idSelect = m_aFlyTarget.GetAt( m_nSelect++ ); CMover *pSelectMover = prj.GetMover( idSelect ); if( IsValidObj(pSelectMover) ) { CWorld *pWorld = pMover->GetWorld(); if( pWorld ) { pWorld->SetObjFocus( pSelectMover ); // 이놈을 타겟으로 설정함. pMover->m_idTracking = pSelectMover->GetId(); // 탭으로 타겟을 바꾸면 자동추적타겟도 그놈으로 바뀐다. } } } } s_bSelectKeyed = g_bKeyTable[VK_TAB]; } if( /*m_bFlyMove &&*/ m_bLButtonDown || g_bKeyTable[VK_INSERT] ) // 192 = ` { CObj *pObj = pMover->GetWorld()->GetObjFocus(); // 타겟잡힌놈이 있을때만 휘두를수 있다. if( pObj && pObj->GetType() == OT_MOVER ) { if( pMover->IsAttackAble( pObj ) ) // 공격 가능한지 검사. { OBJID idTarget = ((CMover *)pObj)->GetId(); ItemProp *pWeapon = pMover->GetActiveHandItemProp(); if( pWeapon ) { g_pPlayer->PlayCombatMusic(); if( pWeapon->dwItemKind3 == IK3_WAND ) { D3DXVECTOR3 vFront, vTarget; AngleToVector( &vFront, g_pPlayer->GetAngle(), -g_pPlayer->GetAngleX(), 1.0f ); vTarget = pObj->GetPos() - g_pPlayer->GetPos(); D3DXVec3Normalize( &vTarget, &vTarget ); // 타겟쪽으로의 벡터의 유닛벡터. FLOAT fDot = D3DXVec3Dot( &vFront, &vTarget ); if( fDot >= cosf(D3DXToRadian(60.0f)) ) // 타겟이 내가 보는 방향의 +-30도 안에 있으면 발사할수 있다. { if( pMover->IsRangeObj( pObj, 64.0f ) ) // 사정거리에 들어오면 발사. { pMover->DoAttackMagic( pObj, 0 ); } } } else { pMover->SendActMsg( OBJMSG_ATK1, idTarget ); } } } } } // fTurnAngle = 0.6f; ItemProp* pItemProp = prj.GetItemProp( g_pPlayer->GetRideItemIdx() ); if( pItemProp ) { fTurnAngle = pItemProp->fFlightLRAngle; } else { Error( "ControlFlying : 빗자루정보 읽기 실패 %d", g_pPlayer->GetRideItemIdx() ); fTurnAngle = 0.6f; } if( bUp ) { if( g_WorldMng.Get()->GetFullHeight( pMover->GetPos() ) < pMover->GetPos().y ) { if( pMover->SendActMsg( OBJMSG_LOOKDOWN ) == 1 ) { fMoved = true; } } } else if( bDown ) { if( pMover->SendActMsg( OBJMSG_LOOKUP ) == 1 ) { fMoved = true; } } else { if( pMover->SendActMsg( OBJMSG_STOP_LOOK ) == 1 ) { fMoved = true; } } if( bLeft ) { m_fRollAng -= 1.0f; if( m_fRollAng < -45.0f ) m_fRollAng = -45.0f; if( pMover->SendActMsg( OBJMSG_LTURN, (int)( fTurnAngle * 100.0f ) ) == 1 ) { fMoved = true; } } else if( bRight ) { m_fRollAng += 1.0f; if( m_fRollAng > 45.0f ) m_fRollAng = 45.0f; if( pMover->SendActMsg( OBJMSG_RTURN, (int)( fTurnAngle * 100.0f ) ) == 1 ) { fMoved = true; } } else { if( m_fRollAng < 0 ) { m_fRollAng += 2.0f; if( m_fRollAng > 0 ) m_fRollAng = 0; } else if( m_fRollAng > 0 ) { m_fRollAng -= 2.0f; if( m_fRollAng < 0 ) m_fRollAng = 0; } if( pMover->SendActMsg( OBJMSG_STOP_TURN ) == 1 ) { fMoved = true; // fBehavior = true; } } // 오른쪽 버튼 드래그는 빗자루 움직임 if( dwMessage == WM_MOUSEMOVE /*&& m_bRButtonDown*/ ) { float fAng = pMover->GetAngle(); float fAdd = (point.x - m_ptMouseOld.x) / 2.0f; fAng -= fAdd; pMover->SetAngle( fAng ); float fAngX = pMover->GetAngleX(); float fAddX = (point.y - m_ptMouseOld.y) / 4.0f; fAngX += fAddX; if( fAddX > 0 && fAngX > 45.0f ) fAngX = 45.0f; else if( fAddX < 0 && fAngX < -45.0f ) fAngX = -45.0f; pMover->SetAngleX( fAngX ); if( fAdd || fAddX ) g_DPlay.PostPlayerAngle( TRUE ); } BOOL bTempKey; if( bTempKey = g_bKeyTable[ '8' ] ) { if( !m_bTemp3ed ) { pMover->SendActMsg( OBJMSG_TEMP2 ); // __bTestLOD ^= 1; } } m_bTemp3ed = bTempKey; if( fMoved ) { g_DPlay.SendPlayerMoved2( nFrame ); } if( fBehavior ) { pMover->ClearDest(); g_DPlay.SendPlayerBehavior2(); } return nMsg; }
void CActionMover::ProcessFlyTracking() { CMover* pMover = m_pMover; // 자동 추적 모드. g_pPlayer만 실행된다. if( pMover->IsActiveMover() && (pMover->m_dwFlag & MVRF_TRACKING) ) { static float s_fTurnAcc = 0, s_fTurnAccH = 0; { CMover *pTarget = prj.GetMover( pMover->m_idTracking ); // 추적할 목표. if( pTarget ) { D3DXVECTOR3 vDist = pTarget->GetPos() - pMover->GetPos(); // 나를 원점으로 타겟까지의 벡터. FLOAT fAngXZ, fAngH; xGetDegree( &fAngXZ, &fAngH, vDist ); // 타겟과의 각도 구함. // 남쪽이 0도 기준. 시계방향 -180까지 시계반대방향 +180 // 3도 이하는 무시. FLOAT fMoverAng = pMover->GetAngle(); if( fMoverAng > 180.0f ) // 계산하기 좋게 좌표계를 +,- 로 바꿈. fMoverAng -= 360.0f; FLOAT fSubAng = fAngXZ - fMoverAng; if( fSubAng > 180.0f ) fSubAng -= 360.0f; else if( fSubAng < -180.0f ) fSubAng += 360.0f; #ifdef _DEBUG #ifdef __XUZHU extern float _g_fReg[]; _g_fReg[1] = fSubAng; _g_fReg[2] = fAngXZ; #endif #endif if( fSubAng < -3.0f ) // 오른쪽으로 돌아야 한다. s_fTurnAcc = -2.5f; else if( fSubAng > 3.0f ) // 왼쪽으로 돌아야 한다. s_fTurnAcc = 2.5f; else s_fTurnAcc = 0; FLOAT fMoverAngX = pMover->GetAngleX(); FLOAT fSubAngH = fAngH - fMoverAngX; if( fSubAngH > 180.0f ) fSubAngH -= 360.0f; else if( fSubAngH < -180.0f ) fSubAngH += 360.0f; if( fSubAngH < -3.0f ) s_fTurnAccH = -1.5f; else if( fSubAngH > 3.0f ) s_fTurnAccH = 1.5f; else s_fTurnAccH = 0; pMover->SetAngle( pMover->GetAngle() + s_fTurnAcc ); pMover->SetAngleX( pMover->GetAngleX() + s_fTurnAccH ); if( s_fTurnAcc || s_fTurnAccH ) // 값이 달라지면 전송함. g_DPlay.PostPlayerAngle( TRUE ); } } } }
void CActionMover::PresupposePos2( D3DXVECTOR3* pv, D3DXVECTOR3* pvd, float* pf, float* pfAngleX, float* pfAccPower, u_long uTickCount ) { CMover* pMover = GetMover(); D3DXVECTOR3 v = pMover->GetPos(); float fAngle = pMover->GetAngle(); D3DXVECTOR3 vDelta = m_vDelta; if( prj.GetItemProp( pMover->m_dwRideItemIdx ) == NULL ) return; float fAcc = prj.GetItemProp( pMover->m_dwRideItemIdx )->fFlightSpeed; // 무버가 타고있는 아이템의 인덱스에서 추진력을 꺼내옴. fAcc *= 0.75f; float fTheta, fThetaX, d; DWORD dwMoveState = GetMoveState(); DWORD dwTurnState = GetTurnState(); DWORD dwLookState = GetLookState(); float fX = pMover->GetAngleX(); float fAccPower = m_fAccPower; float fTurnAngle; D3DXVECTOR3 vAcc; for( u_long i = 0; i < uTickCount; i++ ) { fTheta = D3DXToRadian( fAngle ); switch( dwMoveState ) { case OBJSTA_STAND: fAccPower = 0; break; case OBJSTA_FMOVE: fAccPower = fAcc; break; } switch( dwTurnState ) { case OBJSTA_LTURN: fTurnAngle = m_fTurnAngle; if( ( GetStateFlag() & OBJSTAF_ACC ) == 0 ) fTurnAngle *= 2.5f; fAngle += fTurnAngle; if( fAngle > 360.0f ) fAngle -= 360.0f; break; case OBJSTA_RTURN: fTurnAngle = m_fTurnAngle; if( ( GetStateFlag() & OBJSTAF_ACC ) == 0 ) fTurnAngle *= 2.5f; fAngle -= fTurnAngle; if( fAngle < 0.0f ) fAngle += 360.0f; break; } switch( dwLookState ) { case OBJSTA_LOOKUP: if( fX > -45.0f ) fX -= 1.0f; break; case OBJSTA_LOOKDOWN: if( fX < 45.0f ) fX += 1.0f; break; } fThetaX = D3DXToRadian( fX ); if( GetStateFlag() & OBJSTAF_TURBO ) fAccPower *= 1.5f; d = cosf( fThetaX ) * fAccPower; fTheta = D3DXToRadian( fAngle ); vAcc.x = sinf( fTheta ) * d; vAcc.z = -cosf( fTheta ) * d; vAcc.y = -sinf( fThetaX ) * fAccPower; float fLenSq = D3DXVec3LengthSq( &vDelta ); D3DXVECTOR3 vDeltaNorm, vAccNorm; D3DXVec3Normalize( &vDeltaNorm, &vDelta ); D3DXVec3Normalize( &vAccNorm, &vAcc ); float fDot = D3DXVec3Dot( &vDeltaNorm, &vAccNorm ); if( fAccPower > 0.0f ) { if( fLenSq > 0.01f ) { if( fDot < cosf( 70.0f ) ) { vAcc *= 2.0f; vDelta *= 0.985f; } } } fLenSq = D3DXVec3Length( &vDelta ); if( fLenSq < 0.3f ) { vDelta += vAcc; } vDelta *= ( 1.0f - FRIC_AIR ); v += vDelta; if( v.y > MAX_MOVE_HEIGHT ) v.y = MAX_MOVE_HEIGHT; CWorld* pWorld = GetWorld(); pWorld->ClipX( v.x ); pWorld->ClipZ( v.z ); } *pv = v; *pf = fAngle; *pvd = vDelta; *pfAngleX = fX; *pfAccPower = fAccPower; pMover->m_nCorr = (int)uTickCount; }
DWORD CActionMover::OnDamageMsgC( DWORD dwMsg, CMover* pAttacker, DWORD dwAtkFlags, int nParam ) { CMover* pMover = GetMover(); BOOL bValid = IsValidObj( pMover ) && IsValidObj( pAttacker ); if( !bValid || IsState( OBJSTA_DIE_ALL ) ) return 0; if( IsSit() ) // 앉아있다가 맞으면 앉기해제 한다. ResetState( OBJSTA_MOVE_ALL ); SendActMsg( OBJMSG_STAND ); // 날때린놈에 대한 정보를 기록함. if( pMover->IsNPC() && pAttacker->IsPlayer() ) // 맞은놈은 NPC , 어태커가 플레이어 일때만 적용됨 { pMover->m_idAttacker = pAttacker->GetId(); // 날 때린넘이 어떤놈인가를 기록함. pMover->m_idTargeter = pAttacker->GetId(); } pAttacker->m_idLastHitMover = pMover->GetId(); // 어태커가 마지막으로 때렸던넘이 나란걸 기록함. if( (dwAtkFlags & AF_GENERIC) ) { ItemProp* pAttackerProp = pAttacker->GetActiveHandItemProp(); D3DXVECTOR3 vLocal; if( pAttackerProp && pAttackerProp->dwItemKind3 == IK3_YOYO ) { vLocal = pMover->GetPos(); vLocal.y += 1.0f; } else { AngleToVectorXZ( &vLocal, pAttacker->GetAngle(), 1.0f ); vLocal += pMover->GetPos(); //gmpbigsun : 피격자 일반 effect 09_12_17 vLocal.y += 1.0f; // 2006/6/20 xuzhu } if( pAttackerProp && pAttackerProp->dwSfxObj3 != NULL_ID ) CreateSfx( g_Neuz.m_pd3dDevice, pAttackerProp->dwSfxObj3, vLocal ); if( pAttackerProp && pAttackerProp->dwSfxObj5 != NULL_ID ) //gmpbigsun: 공격자 일반 effect 09_12_17 { vLocal = pAttacker->GetPos( ); CreateSfx( g_Neuz.m_pd3dDevice, pAttackerProp->dwSfxObj5, vLocal ); } } else if ( (dwAtkFlags & AF_MONSTER_SP_CLIENT) ) { // hitter ItemProp* pAttackerProp = prj.GetItemProp( nParam >> 16 ); assert( pAttackerProp ); DWORD dwSfxObj = pAttackerProp->dwSfxObj3; // gmpbigsun:특수공격에 이펙트가 있다면 3번사용. if( dwSfxObj != NULL_ID ) CreateSfx( D3DDEVICE, dwSfxObj, pMover->GetPos() ); // attacker dwSfxObj = pAttackerProp->dwSfxObj5; if( NULL_ID != dwSfxObj ) CreateSfx( D3DDEVICE, dwSfxObj, pAttacker->GetPos() ); }
// // Action Message Process // 액션 메시지를 받아 처리한다. // 어떤 행위가 발생하는 시점에 대한 처리를 담당. // 최적화를 위해서 이미 설정되어 있는 상태면 중복 처리 하지 않음 // int CActionMover::ProcessActMsg1( CMover* pMover, OBJMSG dwMsg, int nParam1, int nParam2, int nParam3, int nParam4, int nParam5 ) { CModelObject* pModel = (CModelObject*)pMover->m_pModel; switch( dwMsg ) { // 평화모드 제자리에 서있어라! case OBJMSG_STAND: #ifdef __Y_INTERFACE_VER3 if( (GetMoveState() == OBJSTA_FMOVE) || (GetMoveState() == OBJSTA_BMOVE) || (GetMoveState() == OBJSTA_LMOVE) || (GetMoveState() == OBJSTA_RMOVE) ) // 전/후진중일때 제자리에 세운다. #else //__Y_INTERFACE_VER3 if( (GetMoveState() == OBJSTA_FMOVE) || (GetMoveState() == OBJSTA_BMOVE) ) // 전/후진중일때 제자리에 세운다. #endif //__Y_INTERFACE_VER3 { ResetState( OBJSTA_MOVE_ALL ); m_vDelta.x = m_vDelta.z = 0; if( pMover->IsFlyingNPC() ) { m_vDelta.y = 0; pMover->SetAngleX(0); } } if( GetMoveState() == OBJSTA_STAND ) return 0; if( GetMoveState() == OBJSTA_PICKUP ) return 0; if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( IsActDamage() ) return -3; if( IsDie() ) return -4; if( IsAction() ) return 0; SetMoveState( OBJSTA_STAND ); pMover->SetMotion( MTI_STAND ); RemoveStateFlag( OBJSTAF_ETC ); break; case OBJMSG_STOP: case OBJMSG_ASTOP: #ifdef __Y_INTERFACE_VER3 if( (GetMoveState() == OBJSTA_FMOVE) || (GetMoveState() == OBJSTA_BMOVE) || (GetMoveState() == OBJSTA_LMOVE) || (GetMoveState() == OBJSTA_RMOVE) ) // 전/후진중일때 제자리에 세운다. #else //__Y_INTERFACE_VER3 if( (GetMoveState() == OBJSTA_FMOVE) || (GetMoveState() == OBJSTA_BMOVE) ) // 전/후진중일때 제자리에 세운다. #endif //__Y_INTERFACE_VER3 { ResetState( OBJSTA_MOVE_ALL ); m_vDelta.x = m_vDelta.z = 0; if( pMover->IsFlyingNPC() ) { m_vDelta.y = 0; pMover->SetAngleX(0); } } pMover->ClearDest(); return 0; // ControlGround에서 키입력없을때 STOP을 부르는데 거기서 리턴값을 맞추기 위해 이렇게 했음. break; case OBJMSG_SITDOWN: if( GetStateFlag() & OBJSTAF_SIT ) return 0; // 이미 앉은모드면 리턴 - 플래그로 검사하지 말고 state로 직접검사하자. if( nParam3 == 0 ) { if( IsActJump() ) return 0; if( IsActAttack() ) return 0; if( IsActDamage() ) return 0; if( IsAction() ) return 0; #ifdef __CLIENT if( pMover->IsActiveMover() && (pMover->m_dwReqFlag & REQ_USESKILL) ) return 0; // 서버로부터 useskill응답이 오기전까진 액션해선 안됨. #endif // __CLIENT } AddStateFlag( OBJSTAF_SIT ); SendActMsg( OBJMSG_STOP ); pMover->SetMotion( MTI_SIT, ANILOOP_CONT ); // 앉기 모션시작 SetMoveState( OBJSTA_SIT ); break; case OBJMSG_STANDUP: if( (GetStateFlag() & OBJSTAF_SIT) == 0 ) return 0; if( nParam3 == 0 ) { if( IsActJump() ) return 0; if( IsActAttack() ) return 0; if( IsActDamage() ) return 0; if( IsAction() ) return 0; #ifdef __CLIENT if( pMover->IsActiveMover() && (pMover->m_dwReqFlag & REQ_USESKILL) ) return 0; // 서버로부터 useskill응답이 오기전까진 액션해선 안됨. #endif // __CLIENT } SetMoveState( OBJSTA_SIT ); AddStateFlag( OBJSTAF_SIT ); pMover->SetMotion( MTI_GETUP, ANILOOP_CONT ); break; case OBJMSG_PICKUP: if( IsSit() ) return 0; if( IsAction() ) return 0; if( IsActJump() ) return 0; if( IsActAttack() ) return 0; if( IsActDamage() ) return 0; #ifdef __CLIENT if( pMover->IsActiveMover() ) { if( pMover->m_dwReqFlag & REQ_USESKILL ) return 0; // 서버로부터 useskill응답이 오기전까진 액션해선 안됨. if( pMover->m_dwReqFlag & REQ_MOTION ) return 0; // 서버로부터 모션 응답이 오기전까지 액션 금지. } #endif // __CLIENT if( GetMoveState() == OBJSTA_PICKUP ) return 0; // 이미 집고 있으면 추가로 실행되지 않게 . SetMoveState( OBJSTA_PICKUP ); pMover->SetMotion( MTI_PICKUP, ANILOOP_1PLAY, MOP_FIXED ); break; case OBJMSG_COLLECT: //if( IsSit() ) return 0; //if( IsAction() ) return 0; //if( IsActJump() ) return 0; //if( IsActAttack() ) return 0; //if( IsActDamage() ) return 0; //SetState( OBJSTA_ACTION_ALL, OBJSTA_COLLECT ); //pMover->SetMotion( MTI_COLLECT, ANILOOP_LOOP, MOP_FIXED ); //pMover->RemoveInvisible(); // 康 // 채집 ClearState(); ResetState( OBJSTA_ACTION_ALL ); SetState( OBJSTA_ACTION_ALL, OBJSTA_COLLECT ); //pMover->m_dwFlag |= MVRF_NOACTION; pMover->SetMotion( MTI_COLLECT, ANILOOP_LOOP, MOP_FIXED ); pMover->RemoveInvisible(); break; case OBJMSG_STUN: SetState( OBJSTA_ACTION_ALL, OBJSTA_STUN ); // 스턴은 어떤 상태에서도 걸릴 수 있으니 상태는 무조것 세팅하자. pMover->m_dwFlag |= MVRF_NOACTION; // 액션 금지 상태로 전환. pMover->m_wStunCnt = (short)nParam1; // 얼마동안이나 스턴상태가 되느냐. if( GetState() == OBJSTA_STAND ) pMover->SetMotion( MTI_GROGGY, ANILOOP_LOOP, MOP_FIXED ); // 아무것도 안하는 스탠딩 상태면 스턴 모션 내자. break; case OBJMSG_FALL: if( IsActJump() ) return 0; // 무적이면 여기서 리턴. if( pMover->m_dwMode & MATCHLESS_MODE ) return 0; pMover->m_dwFlag |= MVRF_NOACTION; // 액션 금지 상태로 전환. if( GetState() != OBJSTA_DMG_FLY ) { SetState( OBJSTA_DMG_ALL, OBJSTA_DMG_FLY ); pMover->SetMotion( MTI_DMGFLY, ANILOOP_LOOP, MOP_FIXED ); } break; // 전진해라! case OBJMSG_TURNMOVE: if( GetMoveState() == OBJSTA_FMOVE && (int)pMover->GetAngle() == nParam1 ) return 0; // 전진 상태이며 각도가 같으면 메시지 무효 if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans if( GetState() & OBJSTA_DMG_FLY_ALL ) // 날라가는 동작중이면 취소 return 0; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; pMover->SetAngle( (float)nParam1 ); if( pMover->IsFlyingNPC() ) pMover->SetAngleX( (float)nParam2 ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_FORWARD ); break; case OBJMSG_TURNMOVE2: if( GetMoveState() == OBJSTA_FMOVE && (int)pMover->GetAngle() == nParam1 ) return 0; // 전진 상태이며 각도가 같으면 메시지 무효 if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans if( IsAction() ) return 0; if( GetState() & OBJSTA_DMG_FLY_ALL ) // 날라가는 동작중이면 취소 return 0; if( IsActJump() ) return -1; // 점프거나 공격 상태면 메시지 무효 처리 if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; pMover->SetAngle( (float)nParam1 ); if( pMover->IsFlyingNPC() ) pMover->SetAngleX( (float)nParam2 ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_BACKWARD ); break; #ifdef __Y_INTERFACE_VER3 case OBJMSG_LFORWARD: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetMoveState() == OBJSTA_LMOVE ) return 0; // 이미 전진상태면 추가로 처리 하지 않음 if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetMoveState( OBJSTA_LMOVE ); if( IsStateFlag( OBJSTAF_WALK ) ) // 걷는모드 { pMover->SetMotion( MTI_WALK ); // 전투모드로 걷기 } else { if( pMover->SetMotion( MTI_RUN ) ) pModel->SetMotionBlending( TRUE ); } break; case OBJMSG_RFORWARD: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetMoveState() == OBJSTA_RMOVE ) return 0; // 이미 전진상태면 추가로 처리 하지 않음 if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetMoveState( OBJSTA_RMOVE ); if( IsStateFlag( OBJSTAF_WALK ) ) // 걷는모드 { pMover->SetMotion( MTI_WALK ); // 전투모드로 걷기 } else { if( pMover->SetMotion( MTI_RUN ) ) pModel->SetMotionBlending( TRUE ); } break; #endif //__Y_INTERFACE_VER3 case OBJMSG_FORWARD: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetMoveState() == OBJSTA_FMOVE ) return 0; // 이미 전진상태면 추가로 처리 하지 않음 if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetMoveState( OBJSTA_FMOVE ); if( IsStateFlag( OBJSTAF_WALK ) ) // 걷는모드 { pMover->SetMotion( MTI_WALK ); } else { if( pMover->SetMotion( MTI_RUN ) ) pModel->SetMotionBlending( TRUE ); } pMover->OnActFMove(); break; case OBJMSG_STOP_RUN: #ifdef __CLIENT if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetMoveState() == OBJSTA_STOP_RUN ) return 0; // 이미 전진상태면 추가로 처리 하지 않음 if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetMoveState( OBJSTA_STOP_RUN ); #endif break; // 후진해라! case OBJMSG_BACKWARD: if( IsActJump() ) return -1; // if jump, x if( IsActAttack() ) return -2; // 공격동작중이면 취소됨. if( IsActDamage() ) return -3; if( GetMoveState() == OBJSTA_BMOVE ) return 0; if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetMoveState( OBJSTA_BMOVE ); pMover->SetMotion( MTI_WALK ); break; // 좌/우 턴 해라! case OBJMSG_LTURN: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetTurnState() == OBJSTA_LTURN ) return 0; if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetTurnState( OBJSTA_LTURN ); break; case OBJMSG_RTURN: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetTurnState() == OBJSTA_RTURN ) return 0; if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetTurnState( OBJSTA_RTURN ); break; case OBJMSG_STOP_TURN: if( GetTurnState() == 0 ) return 0; // 이미 턴 상태가 없다면 처리 안함 SetTurnState( 0 ); // 턴을 중지 break; // 피치를 들어올림. 비행몹의 경우만 사용. case OBJMSG_LOOKUP: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetTurnState() == OBJSTA_LOOKUP ) return 0; if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetLookState( OBJSTA_LOOKUP ); break; case OBJMSG_LOOKDOWN: if( IsActJump() ) return -1; if( IsActAttack() ) return -2; if( GetDmgState() == OBJSTA_DMG ) // 피격 중 명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( GetTurnState() == OBJSTA_LOOKDOWN ) return 0; if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans SetLookState( OBJSTA_LOOKDOWN ); break; case OBJMSG_STOP_LOOK: if( GetLookState() == 0 ) return 0; SetLookState( 0 ); // 룩 중지 break; // 점프 case OBJMSG_JUMP: if( IsActJump() ) return 0; if( IsActAttack() ) return -2; if( IsActDamage() ) return -3; if( IsSit() ) return 0; // 리턴 0으로 해도 되나?. if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans #ifdef __CLIENT if( pMover->IsActiveMover() ) { if( pMover->m_dwReqFlag & REQ_USESKILL ) return 0; // 서버로부터 useskill응답이 오기전까진 점프해선 안됨. if( pMover->m_dwReqFlag & REQ_MOTION ) return 0; // 서버로부터 모션 응답이 오기전까지 점프 금지. } #endif // __CLIENT SendActMsg( OBJMSG_STOP_TURN ); SetJumpState( OBJSTA_SJUMP1 ); if( (GetState() & OBJSTA_COLLECT)== 0 ) pMover->SetMotion( MTI_JUMP1, ANILOOP_1PLAY ); pModel->SetMotionBlending( FALSE ); break; // 완드공격 case OBJMSG_ATK_MAGIC1: // 공격 1 { if( IsAction() ) return 0; if( IsSit() ) // 앉아있는상태였으면 해제 ResetState( OBJSTA_MOVE_ALL ); if( GetState() & OBJSTA_ATK_ALL ) return 0; // 이미 공격동작을 하고 있으면 취소. if( pMover->m_dwFlag & MVRF_NOATTACK ) return -1; // 공격금지 상태면 걍 리턴. if( pMover->IsMode( NO_ATTACK_MODE ) ) return -1; CMover* pHitObj = prj.GetMover( nParam1 ); if( IsInvalidObj( pHitObj ) ) return -1; if( pHitObj->IsDie() ) return -1; #ifdef __WORLDSERVER if( !g_eLocal.GetState( EVE_STEAL ) ) { if( pMover->IsSteal( pHitObj ) ) // pHitObj를 스틸하려하면 이공격은 무시. return -1; } #endif if( IsActDamage() ) ResetState( OBJSTA_DMG_ALL ); if( IsStateFlag( OBJSTAF_COMBAT ) == FALSE ) SendActMsg( OBJMSG_MODE_COMBAT ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_STAND ); SetState( OBJSTA_ATK_ALL, OBJSTA_ATK_MAGIC1 ); pMover->SetMotion( MTI_ATK1, ANILOOP_1PLAY ); // 완드동작이 없으므로 공격동작으로 대신함. pHitObj->SetJJim( pMover ); pMover->m_nAtkCnt = 1; // 카운트 시작. pMover->OnAttackStart( pHitObj, dwMsg ); // 공격시작 핸들러. } break; // 레인지공격 case OBJMSG_ATK_RANGE1: // 공격 1 { if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOATTACK ) return -1; // 공격금지 상태면 걍 리턴. if( pMover->IsMode( NO_ATTACK_MODE ) ) return -1; if( IsSit() ) // 앉아있는상태였으면 해제 ResetState( OBJSTA_MOVE_ALL ); if( GetState() & OBJSTA_ATK_ALL ) return 0; // 이미 공격동작을 하고 있으면 취소. CMover* pHitObj = prj.GetMover( nParam1 ); if( IsValidObj( (CObj*)pHitObj ) == FALSE ) return -1; if( pHitObj->IsDie() ) return -1; m_idTarget = (DWORD)nParam1; // 공격 타겟. #ifdef __WORLDSERVER if( !g_eLocal.GetState( EVE_STEAL ) ) { if( pMover->IsSteal( pHitObj ) ) // pHitObj를 스틸하려하면 이공격은 무시. return -1; } #endif if( GetDmgState() == OBJSTA_DMG ) // 피격 중 공격명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -1; if( IsStateFlag( OBJSTAF_COMBAT ) == FALSE ) SendActMsg( OBJMSG_MODE_COMBAT ); int nUseMotion = nParam2; // SendActMsg( OBJMSG_STOP_TURN ); // SendActMsg( OBJMSG_STAND ); SetState( OBJSTA_ATK_ALL, OBJSTA_ATK_RANGE1 ); pMover->SetMotion( nUseMotion, ANILOOP_1PLAY ); // 완드동작이 없으므로 공격동작으로 대신함. pHitObj->SetJJim( pMover ); // 공격이 시작되면 타겟에다가 내가 찜했다는걸 표시. pMover->OnAttackStart( pHitObj, dwMsg ); // 공격시작 핸들러. pMover->m_nAtkCnt = 1; // 카운트 시작. } break; // 공격 - 리턴값 -2는 클라로 부터 받은 명령을 완전 무시한다. case OBJMSG_ATK1: // 공격 1 case OBJMSG_ATK2: // 공격 2 case OBJMSG_ATK3: // 공격 3 case OBJMSG_ATK4: // 공격 4 { if( IsAction() ) return 0; if( pMover->m_dwFlag & MVRF_NOATTACK ) return -2; // 공격금지 상태면 걍 리턴. if( pMover->IsMode( NO_ATTACK_MODE ) ) return -2; #ifdef __CLIENT if( pMover->IsActiveMover() ) #endif { // 기본은 오른손 검사( 완드용 ) CItemElem* pItemElem = pMover->GetWeaponItem(); if( pItemElem && (pItemElem->GetProp()->dwItemKind3 == IK3_WAND || pItemElem->GetProp()->dwItemKind3 == IK3_BOW ) ) return -2; } CMover* pHitObj = prj.GetMover( nParam1 ); if( IsValidObj( (CObj*)pHitObj ) == FALSE ) return( -1 ); #ifdef __XUZHU if( pMover->IsPlayer() ) { int a = 0; } #endif // xuzhu m_idTarget = (DWORD)nParam1; // 공격 타겟. #ifdef __WORLDSERVER if( !g_eLocal.GetState( EVE_STEAL ) ) { if( pMover->IsSteal( pHitObj ) ) // pHitObj를 스틸하려하면 이공격은 무시. return -2; } #endif if( pHitObj->m_pActMover->IsDie() ) return( -1 ); if( GetState() & OBJSTA_ATK_ALL ) return( 0 ); // 이미 공격중이면 리턴 if( IsSit() ) // 앉아있는상태였으면 해제 ResetState( OBJSTA_MOVE_ALL ); if( GetDmgState() == OBJSTA_DMG ) // 피격 중 공격명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( IsStateFlag( OBJSTAF_COMBAT ) == FALSE ) SendActMsg( OBJMSG_MODE_COMBAT ); SendActMsg( OBJMSG_STOP_TURN ); // 공격할땐 턴을 정지시킴 SendActMsg( OBJMSG_STAND ); DWORD dwOption = MOP_SWDFORCE | MOP_NO_TRANS; #ifdef __XSLOW1018 int nMin, nTemp; pMover->GetHitMinMax( &nMin, &nTemp ); if( dwMsg == OBJMSG_ATK3 || dwMsg == OBJMSG_ATK4 ) if( pMover->GetLevel() >= 12 && pHitObj->GetHitPoint() < (int)(nMin * 1.5f) ) dwOption |= MOP_HITSLOW; #endif // xSlow1018 if( pMover->IsPlayer() ) pMover->m_fAniSpeed = pMover->GetAttackSpeed(); switch( dwMsg ) { case OBJMSG_ATK1: SetState( OBJSTA_ATK_ALL, OBJSTA_ATK1 ); pMover->SetMotion( MTI_ATK1, ANILOOP_1PLAY, dwOption ); // 최초 메시지 입력시 동작 설정 break; case OBJMSG_ATK2: SetState( OBJSTA_ATK_ALL, OBJSTA_ATK2 ); pMover->SetMotion( MTI_ATK2, ANILOOP_1PLAY, dwOption ); // 최초 메시지 입력시 동작 설정 break; case OBJMSG_ATK3: SetState( OBJSTA_ATK_ALL, OBJSTA_ATK3 ); pMover->SetMotion( MTI_ATK3, ANILOOP_1PLAY, dwOption ); // 최초 메시지 입력시 동작 설정 break; case OBJMSG_ATK4: SetState( OBJSTA_ATK_ALL, OBJSTA_ATK4 ); pMover->SetMotion( MTI_ATK4, ANILOOP_1PLAY, dwOption ); // 최초 메시지 입력시 동작 설정 break; } pMover->SetAngle( GetDegree( pHitObj->GetPos(), m_pMover->GetPos() ) ); pHitObj->SetJJim( pMover ); pMover->m_nAtkCnt = 1; // 카운트 시작. pMover->OnAttackStart( pHitObj, dwMsg ); // 공격시작 핸들러. m_objidHit = (OBJID)nParam1; // 타겟의 아이디. m_dwAtkFlags = (DWORD)LOWORD( (DWORD)nParam3 ); #ifdef __WORLDSERVER if( m_dwAtkFlags == 0 ) { if( pMover->GetAttackResult( pHitObj, dwOption ) ) // 공격 성공률을 얻는다. m_dwAtkFlags = AF_GENERIC; else m_dwAtkFlags = AF_MISS; } #else m_dwAtkFlags = AF_GENERIC; // 구조가 좀 이상한데. 클라에서는 명중판정을 하지 않으므로 무조건 평타명중으로 인정. #endif return( (int)m_dwAtkFlags ); break; } // 몬스터들의 특수공격. case OBJMSG_SP_ATK1: case OBJMSG_SP_ATK2: { CMover* pHitObj = prj.GetMover( nParam1 ); //nParam2; // 특수공격에 사용할 무기. 보통은 몬스터이므로 가상아이템이 들어온다. int nUseMotion = nParam3; // 사용할 모션. if( IsValidObj( (CObj*)pHitObj ) == FALSE ) return( -1 ); if( pHitObj->m_pActMover->IsDie() ) return( -1 ); if( GetState() & OBJSTA_ATK_ALL ) return( 0 ); // 이미 공격중이면 리턴 if( pMover->m_dwFlag & MVRF_NOATTACK ) return 0; // 공격금지 상태면 걍 리턴. if( GetDmgState() == OBJSTA_DMG ) // 피격 중 공격명령이면 피격 상태를 클리어 시킨다. ResetState( OBJSTA_DMG_ALL ); else if( GetState() & OBJSTA_DMG_ALL ) // 그외 피격동작은 다 취소 return -3; if( IsStateFlag( OBJSTAF_COMBAT ) == FALSE ) SendActMsg( OBJMSG_MODE_COMBAT ); SendActMsg( OBJMSG_STOP_TURN ); // 공격할땐 턴을 정지시킴 SendActMsg( OBJMSG_STAND ); DWORD dwOption = MOP_SWDFORCE /*| MOP_NO_TRANS*/; // 몬스터니까 공격동작도 모션트랜지션 되게 해봤다. SetState( OBJSTA_ATK_ALL, OBJSTA_SP_ATK1 ); pMover->SetMotion( nUseMotion, ANILOOP_1PLAY, dwOption ); // 최초 메시지 입력시 동작 설정 pMover->SetAngle( GetDegree( pHitObj->GetPos(), m_pMover->GetPos() ) ); pMover->OnAttackStart( pHitObj, dwMsg ); // 공격시작 핸들러. return 1; } break; // 전사들의 근접 전투스킬류 case OBJMSG_MELEESKILL: { if( IsAction() ) return -2; if( pMover->m_dwFlag & MVRF_NOATTACK ) return -2; // 공격금지 상태면 걍 리턴. CMover* pHitObj = prj.GetMover( nParam2 ); if( IsValidObj( pHitObj ) == FALSE ) return -2; #ifdef __WORLDSERVER if( GetState() & OBJSTA_ATK_RANGE1 ) ResetState( OBJSTA_ATK_RANGE1 ); if( GetState() & OBJSTA_ATK_ALL ) return -2; // 이미 공격중이면 리턴. 서버에선 씹히지 않게 하자. pMover->m_dwMotion = -1; // 나머지 경우는 간단하게 생각하기 위해 모두 클리어 시키고 스킬만 실행하자. ClearState(); // 상태 클리어하고 다시 맞춤,. #else // 이리저리 해보니 액티브 무버건 아니건 서버에서 신호오면 바로 시작하는게 좋을거 같애서 이렇게 함. pMover->m_dwMotion = -1; ClearState(); // 상태 클리어하고 다시 맞춤,. #endif SetState( OBJSTA_ATK_ALL, OBJSTA_ATK_MELEESKILL ); // 근접전투스킬상태 설정. DWORD dwMotion = (DWORD)nParam1; int nLoop = ANILOOP_1PLAY; int nSkill = pMover->GetActParam( 0 ); if( nSkill == SI_BLD_DOUBLESW_SILENTSTRIKE || nSkill == SI_ACR_YOYO_COUNTER ) nLoop = ANILOOP_CONT; #ifdef __CLIENT if( pMover->HasBuffByIk3( IK3_TEXT_DISGUISE ) ) dwMotion = MTI_ATK1; #endif pMover->SetMotion( dwMotion, nLoop, MOP_SWDFORCE | MOP_NO_TRANS | MOP_FIXED ); // 해당 동작애니 시작. pMover->OnAttackStart( pHitObj, dwMsg ); // 공격시작 핸들러. m_nMotionHitCount = 0; break; } // 마법사들의 마법스킬류. case OBJMSG_MAGICSKILL: case OBJMSG_MAGICCASTING: { if( IsAction() ) return -2; if( pMover->m_dwFlag & MVRF_NOATTACK ) return -2; // 공격금지 상태면 걍 리턴. CMover* pHitObj = prj.GetMover( nParam2 ); if( IsValidObj( pHitObj ) == FALSE ) return -2; #ifdef __WORLDSERVER if( GetState() & OBJSTA_ATK_ALL ) return -2; // 이미 공격중이면 리턴 #endif pMover->m_dwMotion = -1; ClearState(); // 상태 클리어하고 다시 맞춤. m_nCastingTime = nParam3 * 4; // ProcessAction은 서버/클라 호출 회수 동일하므로, SEC1 사용이 적당하지 않다. #if __VER >= 10 // __LEGEND // 9차 전승시스템 Neuz, World, Trans m_dwCastingEndTick = (DWORD)( GetTickCount() + nParam3 * 66.66F ); m_nCastingTick = (int)( nParam3 * 66.66F ); m_nCastingSKillID = nParam4; #endif //__LEGEND // 9차 전승시스템 Neuz, World, Trans if( m_nCastingTime > 0 ) // 캐스팅 타임이 있을때만... { m_nCount = 0; // 전체 캐스팅 타임은 동작1+동작2의 합이어야 하므로 여기서 카운터를 초기화 한다. SetState( OBJSTA_ATK_ALL, OBJSTA_ATK_CASTING1 ); // 캐스팅부터 시작 -> 발사모션. } else SetState( OBJSTA_ATK_ALL, OBJSTA_ATK_MAGICSKILL ); // 발사모션만. #ifdef __CLIENT if( dwMsg == OBJMSG_MAGICSKILL && pMover->HasBuffByIk3( IK3_TEXT_DISGUISE ) ) nParam1 = MTI_ATK1; #endif pMover->SetMotion( nParam1, ANILOOP_1PLAY, MOP_SWDFORCE | MOP_NO_TRANS | MOP_FIXED ); // 해당 동작애니 시작. pMover->OnAttackStart( pHitObj, dwMsg ); // 공격시작 핸들러. m_nMotionHitCount = 0; break; } //-------------------- 맞았다. case OBJMSG_DAMAGE: case OBJMSG_DAMAGE_FORCE: // 강공격에 맞았다. 날아감. { CMover* pAttacker = PreProcessDamage( pMover, (OBJID)nParam2, nParam4, nParam5 ); if( pAttacker == NULL ) return 0; if( dwMsg == OBJMSG_DAMAGE_FORCE ) // 강공격으로 들어왔을때 if( pMover->CanFlyByAttack() == FALSE ) // 날아가지 못하는 상태면. dwMsg = OBJMSG_DAMAGE; // 일반 데미지로 바꿈. // 실제 가격한 데미지를 리턴함. int nDamage = _ProcessMsgDmg( dwMsg, pAttacker, (DWORD)nParam1, nParam3, nParam4, nParam5 ); #if __VER >= 10 // __METEONYKER_0608 #ifdef __WORLDSERVER #if __VER >= 12 // __NEW_ITEMCREATEMON_SERVER if( pAttacker->IsPlayer() && CCreateMonster::GetInstance()->IsAttackAble( static_cast<CUser*>(pAttacker), pMover ) ) #endif // __NEW_ITEMCREATEMON_SERVER #endif // __WORLDSERVER pMover->PostAIMsg( AIMSG_DAMAGE, pAttacker->GetId(), nDamage ); #endif // __METEONYKER_0608 return nDamage; } break; // HP가 0이 된 순간 호출 case OBJMSG_DIE: { if( IsSit() ) // 앉아있는상태였으면 해제 ResetState( OBJSTA_MOVE_ALL ); ClearState(); // 죽을땐 다른 동작 하고 있던거 다 클리어 시켜버리자. m_vDelta.x = m_vDelta.z = 0; // 죽었으면 델타값 클리어. pMover->RemoveInvisible(); #ifdef __WORLDSERVER pMover->PostAIMsg( AIMSG_DIE, nParam2 ); #endif CMover *pAttacker = (CMover *)nParam2; if( pAttacker ) { if( pMover->IsPlayer() && pAttacker->IsPlayer() ) // 죽은놈과 죽인놈이 플레이어고 { #ifdef __WORLDSERVER if( pMover->m_nDuel == 1 && pMover->m_idDuelOther == pAttacker->GetId() ) // 둘이 듀얼중이었으면 { pMover->ClearDuel(); pAttacker->ClearDuel(); ((CUser*)pMover)->AddSetDuel( pMover ); ((CUser*)pAttacker)->AddSetDuel( pAttacker ); } else if( pMover->m_nDuel == 2 && pMover->m_idDuelParty == pAttacker->m_idparty ) { pMover->m_nDuelState = 300; CMover *pMember; CParty* pParty = g_PartyMng.GetParty( pMover->m_idparty ); if( pParty ) { int i; for( i = 0; i < pParty->m_nSizeofMember; i ++ ) { pMember = (CMover *)g_UserMng.GetUserByPlayerID( pParty->m_aMember[i].m_uPlayerId ); if( IsValidObj( pMember ) ) ((CUser*)pMember)->AddSetDuel( pMover ); } } CParty* pParty2 = g_PartyMng.GetParty( pMover->m_idDuelParty ); if( pParty2 ) { int i; for( i = 0; i < pParty2->m_nSizeofMember; i ++ ) { pMember = (CMover *)g_UserMng.GetUserByPlayerID( pParty2->m_aMember[i].m_uPlayerId ); if( IsValidObj( pMember ) ) ((CUser*)pMember)->AddSetDuel( pMover ); } } } #endif // __WORLDSERVER } if( pAttacker->IsNPC() ) // 공격자가 몹. { // 날때린몹의 어태커가 나일경우는 죽기전에 클리어시켜준다. if( pAttacker->m_idAttacker == pMover->GetId() ) // 공격한몹을 친사람이 나일경우는 스틸체크 해제. { pAttacker->m_idAttacker = NULL_ID; pAttacker->m_idTargeter = NULL_ID; } } } switch( nParam1 ) { #ifdef __BS_DEATH_ACTION case OBJMSG_DAMAGE: case OBJMSG_DAMAGE_FORCE: { int rAngle = 0; int rPower = 0; int nCase = rand() % 6; if( nCase < 3 ) { rAngle = -2; rPower = 10 + rand() % 50; } else if( nCase < 4 ) { rAngle = 10; rPower = 10 + rand() % 50; } else if( nCase < 5 ) { rAngle = 50; rPower = 10 + rand() % 50; } else { rAngle = rand() % 30; rPower = rand() % 200; } if( OBJMSG_DAMAGE_FORCE == nParam1 ) rPower += 50; CMover *pAttacker = (CMover *)nParam2; SetState( OBJSTA_DMG_ALL, OBJSTA_DMG_FLY ); pMover->SetMotion( MTI_DMGFLY, ANILOOP_CONT ); if( pAttacker ) { float faddPower = rPower * 0.01f; float faddAngle = (float)( rAngle ); DoDamageFly( pAttacker->GetAngle(), 100.0f + faddAngle, 0.05f + faddPower ); // 어태커가 보는쪽으로 날려보냄. } } break; #else case OBJMSG_DAMAGE_FORCE: // 강 공격으로 죽었다면 날아가서 죽기 { CMover *pAttacker = (CMover *)nParam2; SetState( OBJSTA_DMG_ALL, OBJSTA_DMG_FLY ); pMover->SetMotion( MTI_DMGFLY, ANILOOP_CONT ); if( pAttacker ) DoDamageFly( pAttacker->GetAngle(), 145.0f, 0.25f ); // 어태커가 보는쪽으로 날려보냄. } break; case OBJMSG_DAMAGE: // 걍 일반 데미지로 죽었다면 그냥 쓰러져 죽기 #endif default: SetState( OBJSTA_DMG_ALL, OBJSTA_DEAD ); pMover->SetMotion( MTI_DIE1, ANILOOP_CONT ); break; } if( !pMover->IsPlayer() ) // 몬스터일 경우. { #ifdef __WORLDSERVER m_nDeadCnt = 60*3; // 디폴트 - 3초 후에 없어짐. MoverProp *pProp = pMover->GetProp(); if( pProp ) { if( pProp->dwSourceMaterial != NULL_ID || pProp->dwClass == RANK_MATERIAL ) // 자원 몹이면.. { if( pProp->dwHoldingTime == NULL_ID ) Error( "%s 의 MoverProp::dwHoldingTime 값이 -1", pMover->GetName() ); m_nDeadCnt = (int)(60.0f * (pProp->dwHoldingTime / 1000.0f)); if( pProp->dwHoldingTime < 10000 ) // 10초 이하일때 Error( "dwHoldingTime : %d %s", pProp->dwHoldingTime, pMover->GetName() ); pMover->m_nCollectOwnCnt = PROCESS_COUNT * 40; CMover *pAttacker = (CMover *)nParam2; if( pAttacker ) pMover->m_idCollecter = pAttacker->GetId(); // 공격자가 소유자가 된다. } { if( pProp->dwSourceMaterial == NULL_ID && pProp->dwClass == RANK_MATERIAL ) // 자원몹인데 자원값이 없는경우 Error( "OBJMSG_DIE : %s %d", pMover->GetName(), pProp->dwSourceMaterial ); if( pProp->dwSourceMaterial != NULL_ID && pProp->dwClass != RANK_MATERIAL ) // 자원몹이 아닌데 자원값이 있는경우. Error( "OBJMSG_DIE 2 : %s %d", pMover->GetName(), pProp->dwSourceMaterial ); } } #endif // WorldServer } break; } case OBJMSG_APPEAR: SetState( OBJSTA_ACTION_ALL, OBJSTA_APPEAR ); pMover->SetMotion( MTI_APPEAR2, ANILOOP_1PLAY, MOP_FIXED | MOP_NO_TRANS ); break; //---- 모드전환 ------------------------ case OBJMSG_MODE_COMBAT: if( GetStateFlag() & OBJSTAF_COMBAT ) return 0; // 이미 전투모드면 리턴 if( IsActJump() ) return 0; if( IsActAttack() ) return 0; if( IsActDamage() ) return 0; if( IsSit() ) return 0; if( IsAction() ) return 0; AddStateFlag( OBJSTAF_COMBAT ); // 전투모드로 서라가 아니고 전투모드로 바꿔라기땜에 서다 명령은 발생시키지 않는다. pMover->m_dwMotion = -1; // 같은 모션을 하라고 한거라 모션이 안바뀌므로 이렇게... pMover->SetMotion( MTI_STAND ); break; case OBJMSG_MODE_PEACE: if( (GetStateFlag() & OBJSTAF_COMBAT) == 0 ) return 0; if( IsActJump() ) return 0; if( IsActAttack() ) return 0; if( IsActDamage() ) return 0; if( IsSit() ) return 0; if( IsAction() ) return 0; RemoveStateFlag( OBJSTAF_COMBAT ); pMover->m_dwMotion = -1; pMover->SetMotion( MTI_STAND ); break; case OBJMSG_MODE_WALK: if( IsSit() ) return 0; if( IsAction() ) return 0; if( GetStateFlag() & OBJSTAF_WALK ) return 0; // 이미 걷기모드면 리턴 AddStateFlag( OBJSTAF_WALK ); break; case OBJMSG_MODE_RUN: if( IsSit() ) return 0; if( IsAction() ) return 0; if( (GetStateFlag() & OBJSTAF_WALK) == 0 ) return 0; // RemoveStateFlag( OBJSTAF_WALK ); break; case OBJMSG_MODE_FLY: { if( nParam3 == 0 ) { if( IsSit() ) return 0; if( IsAction() ) return 0; if( IsActAttack() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans { CWorld* pWorld = pMover->GetWorld(); if( pWorld ) { int nAttr = pMover->GetWorld()->GetHeightAttribute( pMover->GetPos().x, pMover->GetPos().z ); // 이동할 위치의 속성 읽음. if( nAttr == HATTR_NOFLY ) // 비행 금지 지역에서 타려고 하면 못탄다. return 0; } } } AddStateFlag( OBJSTAF_FLY ); ItemProp *pItemProp = prj.GetItemProp( nParam1 ); // 빗자루 프로퍼티. if( pItemProp ) { if( pMover->m_nFuel == -1 ) // 초기값이면 pMover->m_nFuel = (int)pItemProp->dwFFuelReMax; // 빗자루 최대 연료량을 세팅. // -1일때만 세팅해야지 연료를 반쯤 쓰다가 빗자루를 바꿔도 새로 세팅 되지 않는다. } #ifndef __JEFF_9_20 #ifdef __WORLDSERVER if( pMover->IsPlayer() ) { ((CUser*)pMover)->SetFlyTimeOn(); } #endif // __WORLDSERVER #endif // __JEFF_9_20 ClearState(); #ifdef __CLIENT if( m_pMover == CMover::GetActiveMover() ) { m_pMover->GetWorld()->SetObjFocus( NULL ); // 비행직전에 기존타겟팅을 클리어해준다. g_Neuz.m_camera.Unlock(); g_WndMng.m_pWndTaskBar->OnCancelSkill(); // 비행직전엔 스킬바 사용 취소. } #endif CModel* pModel = prj.m_modelMng.LoadModel( D3DDEVICE, OT_ITEM, (DWORD) nParam1 ); #if __VER >= 14 // __WING_ITEM CModelObject* pModelObject = (CModelObject*)pModel; if( pModelObject->m_pBone ) { CString strMotion = pModelObject->GetMotionFileName( _T("stand") ); assert( strMotion != _T("") ); pModelObject->LoadMotion( strMotion ); } #endif // __WING_ITEM m_pMover->SetRide( pModel, (DWORD) nParam1 ); break; } case OBJMSG_MOTION: // 단순 모션 플레이 { if( IsSit() ) return 0; if( IsAction() ) return 0; if( IsActJump() ) return 0; if( IsActAttack() ) return 0; if( IsActDamage() ) return 0; if( pMover->m_dwFlag & MVRF_NOMOVE ) return 0; // 이동금지 상태면 걍 리턴. #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pMover->GetAdjParam( DST_CHRSTATE ) & CHS_LOOT) return 0; #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans AddStateFlag( OBJSTAF_ETC ); // 단순 모션 플레이 상태 m_nMotionEx = nParam1; // 모션 인덱스 int nPlayMode = nParam2; // 루핑 모드. if( m_nMotionEx != -1 ) pMover->SetMotion( m_nMotionEx, nPlayMode, MOP_FIXED/* | MOP_SWDFORCE*/ ); pMover->RemoveInvisible(); } break; // 일반 액션. case OBJMSG_RESURRECTION: // 부활. ClearState(); SetState( OBJSTA_DMG_ALL, OBJSTA_RESURRECTION ); pMover->SetMotion( MTI_ASS_RESURRECTION, ANILOOP_1PLAY, MOP_FIXED ); break; #if defined(_DEBUG) && defined(__CLIENT) case OBJMSG_TEMP: { for( int i=0; i < 1; i ++ ) { CMover* pObj = new CMover; D3DXVECTOR3 vPos = pMover->GetPos(); pObj->SetPos( vPos ); pObj->SetIndex( g_Neuz.m_pd3dDevice, MI_AIBATT1, TRUE ); pObj->SetMotion( 0 ); g_WorldMng.Get()->AddObj( pObj, TRUE ); } } break; case OBJMSG_TEMP2: // 디버깅용 공격동작만 볼때. if( CMover::GetActiveMover()->IsAuthHigher( AUTH_GAMEMASTER ) ) // 영자 계정일때 { CObj *pObj = pMover->GetWorld()->GetObjFocus(); g_DPlay.SendCorrReq( pObj ); g_DPlay.SendError( FE_GENERAL, 0 ); } break; case OBJMSG_TEMP3: { #ifdef __XUZHU g_DPlay.SendError( 0, 0 ); #endif } break; #endif // defined(_DEBUG) && defined(__CLIENT) } return 1; }