// // // 클라이언트용 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 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 ); } } } } } }