void CShip::Control( void ) { #ifdef __CLIENT static BOOL s_bAcced = 0; static BOOL s_bLefted = 0; static BOOL s_bRighted = 0; static BOOL s_bBoarded = 0; BOOL bAcc = g_bKeyTable[ VK_SPACE ]; BOOL bLeft = g_bKeyTable[g_Neuz.Key.chLeft]; BOOL bDown = g_bKeyTable[ g_Neuz.Key.chUp ]; BOOL bRight = g_bKeyTable[ 'D' ]; BOOL bUp = g_bKeyTable[ 'S' ]; BOOL bBoard = g_bKeyTable[ 'B' ]; if( bAcc && !s_bAcced ) // 가속/정지 토글. { if( m_Act.GetMoveState() == OBJSTA_FMOVE ) // 전진중이라면 SendActMsg( OBJMSG_STOP ); // 멈추고 else SendActMsg( OBJMSG_FORWARD ); // 아니라면 전진시작. } s_bAcced = bAcc; if( bLeft ) { SendActMsg( OBJMSG_LTURN ); // 왼쪽으로 턴 } else if( bRight ) { SendActMsg( OBJMSG_RTURN ); // 오른쪽으로 턴. } else { SendActMsg( OBJMSG_STOP_TURN ); // 좌/우키가 안눌려져있다면 회전 정지. } if( bUp ) { SendActMsg( OBJMSG_LOOKUP ); } else if( bDown ) { SendActMsg( OBJMSG_LOOKDOWN ); } else { SendActMsg( OBJMSG_STOP_LOOK ); // 위/아래 키가 안눌려져있다면 상승/하강 정지. } if( bBoard && !s_bBoarded ) // 배 조종을 해제하기. { g_pShip = NULL; SetMover( NULL ); } s_bBoarded = bBoard; #endif // CLIENT }
bool vMover::SetStun(bool bApply, DWORD dwMaxTime) { if( bApply ) { MoverProp* pMoverProp = GetProperty(); if( pMoverProp->dwClass == RANK_SUPER || pMoverProp->dwClass == RANK_MIDBOSS ) return false; if( GetAdjParam( DST_IMMUNITY ) & CHS_STUN ) return false; SetDestParam( DST_CHRSTATE, CHS_STUN, NULL_CHGPARAM, FALSE ); SendActMsg( OBJMSG_STUN ); m_wStunCnt = (short)( (dwMaxTime / 1000.0f) * PROCESS_COUNT ); } else { if( GetAdjParam( DST_CHRSTATE ) & CHS_STUN ) ResetDestParam( DST_CHRSTATE, CHS_STUN, false); m_wStunCnt = 0; m_dwFlag &= (~MVRF_NOACTION); } g_pUserMng.AddSetStun( this, dwMaxTime ); return true; }
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() ); }
// // // 클라이언트용 void CMover::ProcessMoveArrival( CCtrl *pObj ) { // 클라이언트 처리 if( IsActiveMover() ) { switch( m_oaCmd ) // 목표에 도착한 후의 명령 처리. { case OBJACT_USESKILL: if( pObj->GetType() == OT_MOVER && ( m_SkillTimerStop || m_SkillTimer.TimeOut() ) ) { CWorld *pWorld = GetWorld(); D3DXVECTOR3 vStart = GetPos(); vStart.y += 0.5f; D3DXVECTOR3 vEnd = pObj->GetPos(); vEnd.y += 0.5f; if( pWorld->IntersectObjLine( NULL, vStart, vEnd, FALSE, FALSE ) ) { g_WndMng.PutString( prj.GetText( TID_GAME_BLOCKTARGETING ), NULL, prj.GetTextColor( TID_GAME_BLOCKTARGETING ) ); g_WndMng.m_pWndWorld->SetNextSkill( NEXTSKILL_NONE ); break; } PlayCombatMusic(); int nSkillIdx = GetCmdParam(0); OBJID idTarget = (OBJID)GetCmdParam(1); SKILLUSETYPE sutType = (SKILLUSETYPE)GetCmdParam(2); if( (m_dwReqFlag & REQ_USESKILL) == 0 ) // 응답 요청중일땐 다시 보내선 안된다. { LPSKILL pSkill = GetSkill( 0, nSkillIdx ); // this가 가진 스킬중 nIdx에 해당하는 스킬을 꺼낸다. if( pSkill == NULL ) { Error( "CMD_SetUseSkill : %s skill(%d) not found", m_szName, nSkillIdx ); return; // skill not found } if( pSkill->dwSkill == SI_MAG_MAG_BLINKPOOL ) { CWndWorld* pWndWorld; pWndWorld = (CWndWorld*)g_WndMng.m_pWndWorld; { vStart = GetPos(); vStart.y += 1.0f; vEnd = pWndWorld->m_vTelePos; if( pWorld->IntersectObjLine( NULL, vStart, vEnd, FALSE, FALSE ) ) { g_WndMng.m_pWndWorld->SetNextSkill( NEXTSKILL_NONE ); g_WndMng.PutString( prj.GetText( TID_GAME_BLOCKTARGETING ), NULL, prj.GetTextColor( TID_GAME_BLOCKTARGETING ) ); break; } } if(g_pMoveMark!=NULL) g_pMoveMark->m_pSfxObj->m_nCurFrame=180; CreateSfx(g_Neuz.m_pd3dDevice,XI_GEN_MOVEMARK01,pWndWorld->m_vTelePos); } // 뒤에서 공격가능한 스킬인지 판단한다 // 강탈 스킬은 뒤에서 사용가능(일단 클라에서 판정하자~) if( pSkill->GetProp() && pSkill->GetProp()->dwAtkStyle == AS_BACK ) { D3DXVECTOR3 v3Pos; D3DXVECTOR3 v3PosSrc; D3DXVECTOR3 v3PosDest; // 방향벡터 1 v3PosSrc = pObj->GetPos() - GetPos(); D3DXVec3Normalize( &v3PosSrc, &v3PosSrc ); // 방향벡터 2 AngleToVectorXZ( &v3Pos, pObj->GetAngle(), 3.0f ); v3PosDest = (pObj->GetPos()+v3Pos) - pObj->GetPos(); D3DXVec3Normalize( &v3PosDest, &v3PosDest ); FLOAT fDir = D3DXVec3Dot( &v3PosSrc, &v3PosDest ); // 뒤가 아니면 스킬 사용 불가! if( fDir < 0.3f ) { g_WndMng.PutString( prj.GetText(TID_GAME_NEVERKILLSTOP) ); break; } } #if __VER >= 8 // __S8_PK // 카오에게 좋은 스킬을 사용할때는 Control 키를 눌러야 함 if( g_eLocal.GetState( EVE_PK ) ) { CMover * pMover; pMover = prj.GetMover( idTarget ); if( IsValidObj(pMover) && pMover != g_pPlayer && pMover->IsPlayer() && pMover->IsChaotic() ) if( pSkill->GetProp()->nEvildoing > 0 ) // 좋은 스킬 if( !(GetAsyncKeyState(VK_CONTROL) & 0x8000) ) break; } #endif // __VER >= 8 // __S8_PK TRACE( "OBJACT_USESKILL %d\n", nSkillIdx ); #if __VER >= 8 // __S8_PK BOOL bControl = ((GetAsyncKeyState(VK_CONTROL) & 0x8000)? TRUE:FALSE); g_DPlay.SendUseSkill( 0, nSkillIdx, idTarget, sutType, bControl ); // 목표지점에 도착하면 스킬쓴다고 알림. #else // __VER >= 8 // __S8_PK g_DPlay.SendUseSkill( 0, nSkillIdx, idTarget, sutType ); // 목표지점에 도착하면 스킬쓴다고 알림. #endif // __VER >= 8 // __S8_PK m_dwReqFlag |= REQ_USESKILL; // 응답 요청중 } ClearDestObj(); // 목표에 도달하면 추적을 멈춤. SendActMsg( OBJMSG_STOP ); if( !m_SkillTimerStop ) m_SkillTimer.Reset(); } break; //------------------------------------------ case OBJACT_MELEE_ATTACK: if( pObj->GetType() == OT_MOVER ) { ItemProp *pItemProp = GetActiveHandItemProp(); if( pItemProp && pItemProp->dwItemKind3 == IK3_YOYO ) { CWorld *pWorld = GetWorld(); D3DXVECTOR3 vStart = GetPos(); vStart.y += 0.5f; D3DXVECTOR3 vEnd = pObj->GetPos(); vEnd.y += 0.5f; if( pWorld->IntersectObjLine( NULL, vStart, vEnd, FALSE, FALSE ) ) { g_WndMng.PutString( prj.GetText( TID_GAME_BLOCKTARGETING ), NULL, prj.GetTextColor( TID_GAME_BLOCKTARGETING ) ); break; } } DoAttackMelee( (CMover *)pObj ); // pObj를 일반공격. } break; //--------------------------------------------- case OBJACT_MAGIC_ATTACK: if( pObj->GetType() == OT_MOVER ) { PlayCombatMusic(); OBJID idTarget = GetCmdParam(0); int nMagicPower = GetCmdParam(1); CMover *pTarget = prj.GetMover( idTarget ); // 타겟의 아이디를 포인터로 읽음. if( IsInvalidObj(pTarget) ) break; // 타겟이 거시기한 포인터면 취소시킴. SendActMsg( OBJMSG_STAND ); ClearDestObj(); // 목표에 도달하면 추적을 멈춤. DoAttackMagic( pTarget, nMagicPower ); } break; case OBJACT_RANGE_ATTACK: { if( pObj->GetType() == OT_MOVER ) { PlayCombatMusic(); OBJID idTarget = GetCmdParam(0); int nPower = GetCmdParam(1); CMover *pTarget = prj.GetMover( idTarget ); // 타겟의 아이디를 포인터로 읽음. if( IsInvalidObj(pTarget) ) break; // 타겟이 거시기한 포인터면 취소시킴. SendActMsg( OBJMSG_STAND ); SendActMsg( OBJMSG_STOP_TURN ); ClearDestObj(); // 목표에 도달하면 추적을 멈춤. DoAttackRange( pTarget, nPower, 0 ); // nPower를 dwItemID에 넣는다. } } break; //--------------------------------------------- case OBJACT_USEITEM: ClearDestObj(); // 그외는 목표에 도착하면 멈춤. SendActMsg( OBJMSG_STAND ); SetAngle( GetDegree(pObj->GetPos(), GetPos()) ); // 목표쪽으로 몸을 돌림. break; //--------------------------------------------- case OBJACT_COLLECT: ClearDestObj(); // 그외는 목표에 도착하면 멈춤. SendActMsg( OBJMSG_STOP ); SetAngle( GetDegree(pObj->GetPos(), GetPos()) ); // 목표쪽으로 몸을 돌림. g_DPlay.SendDoCollect( pObj ); // 서버로 보냄. break; //--------------------------------------------- default: ClearDestObj(); // 그외는 목표에 도착하면 멈춤. SendActMsg( OBJMSG_STOP ); break; } SetCmd( OBJACT_NONE ); } else { BOOL bQuery = m_pActMover->IsMove(); ClearDestObj(); // 그외는 목표에 도착하면 멈춤. SendActMsg( OBJMSG_STOP ); OnArrive( pObj->GetId(), 0 ); if( bQuery ) g_DPlay.SendQueryGetDestObj( this ); } }
// 패턴이동중. void CMover::ProcessMovePattern( void ) { if( m_nMovePattern == 1 ) // 8자이동 패턴. { switch( m_nMoveEvent ) { case 0: m_nMoveEvent ++; m_nMoveEventCnt = 0; // break; // break 넣지 말것. case 1: // S - 1 구간 : n초간 좌회전중. SendActMsg( OBJMSG_FORWARD ); if( (m_nMoveEventCnt & 3) == 0 ) SendActMsg( OBJMSG_LTURN ); else SendActMsg( OBJMSG_STOP_TURN ); if( ++m_nMoveEventCnt > SEC1 * 2 ) { m_nMoveEventCnt = 0; m_nMoveEvent ++; // SendActMsg( OBJMSG_STOP ); } break; case 2: // 1 - 2구간 : n초간 우회전하며 상승했다 하강. SendActMsg( OBJMSG_FORWARD ); if( (m_nMoveEventCnt & 3) == 0 ) SendActMsg( OBJMSG_RTURN ); else SendActMsg( OBJMSG_STOP_TURN ); if( m_nMoveEventCnt < (SEC1 * 5) / 2 ) { SendActMsg( OBJMSG_LOOKUP ); } else if( m_nMoveEventCnt == (SEC1 * 5) / 2 ) { SendActMsg( OBJMSG_STOP_LOOK ); SetAngleX( 0 ); // 수평으로 맞춤. } else { SendActMsg( OBJMSG_LOOKDOWN ); } if( ++m_nMoveEventCnt > SEC1 * 5 ) { m_nMoveEventCnt = 0; m_nMoveEvent ++; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_STOP ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 3: // 2 - 3구간 : 우회전 하다가 좌회전. SendActMsg( OBJMSG_FORWARD ); if( m_nMoveEventCnt < (SEC1 * 5) / 2 ) // { if( (m_nMoveEventCnt & 3) == 0 ) SendActMsg( OBJMSG_RTURN ); else SendActMsg( OBJMSG_STOP_TURN ); } else { if( (m_nMoveEventCnt & 3) == 0 ) SendActMsg( OBJMSG_LTURN ); else SendActMsg( OBJMSG_STOP_TURN ); } if( ++m_nMoveEventCnt > SEC1 * 5 ) { m_nMoveEventCnt = 0; m_nMoveEvent ++; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 4: // 3 - S구간 : 좌회전하면서 하강하다 상승 SendActMsg( OBJMSG_FORWARD ); if( (m_nMoveEventCnt & 3) == 0 ) SendActMsg( OBJMSG_LTURN ); else SendActMsg( OBJMSG_STOP_TURN ); if( m_nMoveEventCnt < (SEC1 * 5) / 2 ) { SendActMsg( OBJMSG_LOOKDOWN ); } else if( m_nMoveEventCnt == (SEC1 * 5) / 2 ) { SendActMsg( OBJMSG_STOP_LOOK ); SetAngleX( 0 ); // 수평으로 맞춤. } else { SendActMsg( OBJMSG_LOOKUP ); } if( ++m_nMoveEventCnt > SEC1 * 5 ) { m_nMoveEventCnt = 0; m_nMoveEvent = 99; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_STOP ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 99: break; } } else // movePattern 1 if( m_nMovePattern == 2 ) // 비행 패턴 2 { switch( m_nMoveEvent ) { case 0: m_nMoveEvent ++; m_nMoveEventCnt = 0; // break; // break 넣지 말것. case 1: // S - 1 구간중 직진 코스 SendActMsg( OBJMSG_FORWARD ); if( ++m_nMoveEventCnt > SEC1 ) // 1초가 지나면 급 우회전. { FLOAT fAngle = GetAngle(); SetAngle( fAngle + 135.0f ); m_nMoveEventCnt = 0; m_nMoveEvent ++; } break; case 2: // 1구간중 우/하로 이동 SendActMsg( OBJMSG_FORWARD ); if( ++m_nMoveEventCnt > SEC1 * 2 ) // 2초간 직진하다가 다시 좌로 90도 회전. { FLOAT fAngle = GetAngle(); SetAngle( fAngle - 90.0f ); m_nMoveEventCnt = 0; m_nMoveEvent ++; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_STOP ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 3: // 1구간중 3번째 구간 SendActMsg( OBJMSG_FORWARD ); if( ++m_nMoveEventCnt > SEC1 * 2 ) { FLOAT fAngle = GetAngle(); SetAngle( fAngle - 45.0f ); m_nMoveEventCnt = 0; m_nMoveEvent ++; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 4: // 2-1 구간 SendActMsg( OBJMSG_FORWARD ); if( ++m_nMoveEventCnt > SEC1 * 1 ) { FLOAT fAngle = GetAngle(); SetAngle( fAngle - 45.0f ); m_nMoveEventCnt = 0; m_nMoveEvent ++; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_STOP ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 5: // 2-2 구간 SendActMsg( OBJMSG_FORWARD ); if( ++m_nMoveEventCnt > SEC1 * 3 ) { FLOAT fAngle = GetAngle(); SetAngle( fAngle + 45.0f ); m_nMoveEventCnt = 0; m_nMoveEvent = 99; SendActMsg( OBJMSG_STOP_LOOK ); SendActMsg( OBJMSG_STOP_TURN ); SendActMsg( OBJMSG_STOP ); SetAngleX( 0 ); // 수평으로 맞춤. } break; case 99: break; } } // MovePattern 2 }
// 이 함수.. 오브젝트 서브 클래스로 분리 예정.. void CMover::ProcessMove() { if( m_pActMover->IsSit() ) return; EnforcedGhostCorr(); // 고스트의 강제 동기가 필요하다면 실행 ApproachGhostAngle(); // 고스트의 목표 각도로의 점진적인 각도의 변경 if( IsEmptyDest() ) return; if( m_pActMover->IsActAttack() ) return; D3DXVECTOR3 vPos = GetPos(); D3DXVECTOR3 vDestPos = m_vDestPos; if( !IsEmptyDestPos() ) // 좌표 { bool bPositiveX = ( (vPos.x - vDestPos.x) > 0.0f ); bool bPositiveZ = ( (vPos.z - vDestPos.z) > 0.0f ); #ifdef __BS_FIX_ARRIVEPOS_ALGO // 마우스 목적좌표 이동시 절대축과 같은경우 중간에 멈추는 현상이 있었다. if( ( bPositiveX != m_bPositiveX || bPositiveZ != m_bPositiveZ ) ) { if( IsActiveMover( ) ) { D3DXVECTOR3 kDir = vPos - vDestPos ; D3DXVec3Normalize( &kDir, &kDir ); D3DXVECTOR3 kMyDir; AngleToVectorXZ( &kMyDir, GetAngle(), 1.0f ); D3DXVec3Normalize( &kMyDir, &kMyDir ); float fAngle = D3DXVec3Dot( &kDir, &kMyDir ); if( fAngle > 0.0f ) { OnArriveAtPos( ); return; } } else { OnArriveAtPos( ); return; } } #else if( ( bPositiveX != m_bPositiveX || bPositiveZ != m_bPositiveZ ) ) { OnArriveAtPos(); // 좌표에 도착했을 때의 처리 return; } #endif } else // 오브젝트 { CCtrl* pObj = prj.GetCtrl( m_idDest ); if( IsValidObj( pObj ) == FALSE ) { SendActMsg( OBJMSG_STAND ); return; } vDestPos = pObj->GetPos(); if( m_pActMover->IsFly() ) { BOOL bRangeObj = pObj->IsRangeObj( this, m_fArrivalRange ); if( bRangeObj == TRUE ) { ClearDestObj(); // 그외는 목표에 도착하면 멈춤. #ifdef __WORLDSERVER OnArrive( pObj->GetId(), 0 ); #endif // __WORLDSERVER } } else { if( pObj->IsRangeObj( this, m_fArrivalRange ) ) // 3D 충돌에 실패했지만 { ProcessMoveArrival( pObj ); return; } } } // 공중 추적 if( m_pActMover->IsFly() ) { if( m_uRemnantCorrFrm > 0 ) { D3DXVECTOR3 v = vDestPos - vPos; m_pActMover->m_fDistance = D3DXVec3Length( &v ); SendActMsg( OBJMSG_TURNMOVE, (int)GetDegree( vDestPos, vPos ), (int)GetDegreeX( vDestPos, vPos ), 0 ); m_uRemnantCorrFrm--; } } else { if( m_uRemnantCorrFrm > 0 ) m_uRemnantCorrFrm--; if( m_bForward ) SendActMsg( OBJMSG_TURNMOVE, (int)GetDegree( vDestPos, vPos ), (int)GetDegreeX( vDestPos, vPos ) ); else SendActMsg( OBJMSG_TURNMOVE2, (int)GetDegree( vPos, vDestPos ), (int)GetDegreeX( vPos, vDestPos ) ); } }
// // // 월드서버용 void CMover::ProcessMoveArrival( CCtrl *pObj ) { switch( m_oaCmd ) // 목표에 도착한 후의 명령 처리. { case OBJACT_USESKILL: if( pObj->GetType() == OT_MOVER ) // 타겟이 무버일때면 처리함. { int nSkillIdx = GetCmdParam(0); OBJID idTarget = (OBJID)GetCmdParam(1); SKILLUSETYPE sutType = (SKILLUSETYPE)GetCmdParam(2); LPSKILL pSkill = GetSkill( 0, nSkillIdx ); // this가 가진 스킬중 nIdx에 해당하는 스킬을 꺼낸다. if( pSkill == NULL ) { Error( "ProcessMoveArrival mover:%s skill(%d) not found.", m_szName, nSkillIdx ); return; // skill not found } #if __VER >= 10 // __LEGEND // 10차 전승시스템 Neuz, World, Trans if( pSkill->dwSkill == SI_MAG_MAG_BLINKPOOL || pSkill->dwSkill == SI_RIG_HERO_RETURN ) #else //__LEGEND // 10차 전승시스템 Neuz, World, Trans if( pSkill->dwSkill == SI_MAG_MAG_BLINKPOOL ) #endif //__LEGEND // 10차 전승시스템 Neuz, World, Trans return; // 아직 서버명령으로는 블링크풀 사용못함. CWorld *pWorld = GetWorld(); D3DXVECTOR3 vStart = GetPos(); vStart.y += 0.5f; D3DXVECTOR3 vEnd = pObj->GetPos(); vEnd.y += 0.5f; if( pWorld->IntersectObjLine( NULL, vStart, vEnd, FALSE, FALSE ) ) // 시전자와 타겟사이 장애물을 검사. { if( IsPlayer() ) ((CUser *)this)->AddDefinedText( TID_GAME_BLOCKTARGETING, "" ); break; } #if __VER >= 8 // __S8_PK BOOL bSuccess = DoUseSkill( 0, nSkillIdx, idTarget, sutType, FALSE ); // 목표지점에 도착하면 스킬 사용시작. #else // __VER >= 8 // __S8_PK BOOL bSuccess = DoUseSkill( 0, nSkillIdx, idTarget, sutType ); // 목표지점에 도착하면 스킬 사용시작. #endif // __VER >= 8 // __S8_PK if( bSuccess == FALSE ) if( IsPlayer() ) ((CUser *)this)->m_playTaskBar.OnEndSkillQueue( (CUser *)this ); ClearDestObj(); // 목표에 도달하면 추적을 멈춤. SendActMsg( OBJMSG_STOP ); } break; default: SendActMsg( OBJMSG_STOP ); ClearDestObj(); // 목표에 도달하면 추적을 멈춤. OnArrive( pObj->GetId(), 0 ); break; } // switch SetCmd( OBJACT_NONE ); if( IsPlayer() ) ((CUser*)this)->AddQueryGetDestObj( NULL_ID ); }
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 }
// // 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; }