void CParty::DoUsePartySkill( u_long uPartyId, u_long uLeaderid, int nSkill ) { #ifdef __WORLDSERVER CUser* pMember = NULL; int i; if( IsLeader( uLeaderid ) && m_nKindTroup == 1 ) { ItemProp* pItemProp = prj.GetPartySkill( nSkill ); if( pItemProp ) { #ifndef __PARTYDEBUG if( int( GetLevel() - pItemProp->dwReqDisLV ) >= 0 ) #endif // __PARTYDEBUG { #ifndef __PARTYDEBUG #if __VER >= 12 // __JHMA_VER12_1 //12차 극단유료아이템 CUser *pLeadertmp = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeadertmp ) == FALSE ) return; int nHasCashSkill = 0,nFPoint = 0; if( pLeadertmp->HasBuff( BUFF_ITEM2, II_SYS_SYS_SCR_PARTYSKILLUP01 ) || pLeadertmp->HasBuff( BUFF_ITEM2, II_SYS_SYS_SCR_PARTYSKILLUP02 ) || pLeadertmp->HasBuff( BUFF_ITEM2, II_SYS_SYS_SCR_PARTYSKILLUP01_01 ) ) { if( nSkill == ST_LINKATTACK || nSkill == ST_FORTUNECIRCLE || nSkill == ST_STRETCHING || nSkill == ST_GIFTBOX ) nHasCashSkill = 1; } DWORD dwSkillTime = pItemProp->dwSkillTime; int nRemovePoint = pItemProp->dwExp; nFPoint = int( GetPoint() - pItemProp->dwExp); #if __VER >= 12 // __LORD // 군주의 극단 // 군주가 극단장 으로써 극단스킬 사용 시, // 지속시간 4배 증가(소모 포인트는 동일) if( CSLord::Instance()->IsLord( uLeaderid ) ) dwSkillTime *= 4; #endif // __LORD if( nFPoint >= 0 ) #else if( int( GetPoint() - pItemProp->dwExp) >= 0 ) #endif // //12차 극단유료아이템 #endif // __PARTYDEBUG { switch( nSkill ) { case ST_CALL: { g_DPCoreClient.SendRemovePartyPoint( uPartyId, pItemProp->dwExp ); CUser *pLeader = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeader ) == FALSE ) break; // 단장 중심으로 모여달라는 표시 for( i = 0; i < m_nSizeofMember; i ++ ) // 단장(0)에게는 보낼필요 없다. { pMember = g_UserMng.GetUserByPlayerID( m_aMember[i].m_uPlayerId ); // 단장 어라운드 지역에 있는 사람에게만 보낸다 if( IsValidObj( (CObj*)pMember ) ) pMember->AddPartySkillCall( pLeader->GetPos() ); // 각 멤버들에게 단장이 좌표를 전송함. } } break; case ST_BLITZ: { CUser *pLeader = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeader ) == FALSE ) break; if( pLeader->m_idSetTarget != NULL_ID ) { CMover *pT = prj.GetMover( pLeader->m_idSetTarget ); if( pT && !pT->IsPlayer() ) { g_DPCoreClient.SendRemovePartyPoint( uPartyId, pItemProp->dwExp ); // 단장이 타겟으로 집중공격 표시 for( i = 0; i < m_nSizeofMember; i ++ ) { pMember = g_UserMng.GetUserByPlayerID( m_aMember[i].m_uPlayerId ); if( IsValidObj( (CObj*)pMember ) ) { if( m_nModeTime[PARTY_GIFTBOX_MODE] || m_nModeTime[PARTY_FORTUNECIRCLE_MODE] ) { pMember->AddPartySkillBlitz( pLeader->m_idSetTarget ); // 각 멤버들에게 단장타겟으로 잡은 무버의 아이디를 보냄. } else { if( pLeader->IsNearPC( pMember ) ) pMember->AddPartySkillBlitz( pLeader->m_idSetTarget ); // 각 멤버들에게 단장타겟으로 잡은 무버의 아이디를 보냄. } } } } else { pLeader->AddSendErrorParty( ERROR_NOTTARGET, ST_BLITZ ); } } else { pLeader->AddSendErrorParty( ERROR_NOTTARGET, ST_BLITZ ); // 타겟을 안잡았다. } } break; case ST_RETREAT: { g_DPCoreClient.SendRemovePartyPoint( uPartyId, pItemProp->dwExp ); // 후퇴 표시 CUser *pLeader = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeader ) == FALSE ) break; for( i = 0; i < m_nSizeofMember; i ++ ) { pMember = g_UserMng.GetUserByPlayerID( m_aMember[i].m_uPlayerId ); if( IsValidObj( (CObj*)pMember ) ) { if( m_nModeTime[PARTY_GIFTBOX_MODE] || m_nModeTime[PARTY_FORTUNECIRCLE_MODE] ) { pMember->AddHdr( pMember->GetId(), SNAPSHOTTYPE_PARTYSKILL_RETREAT ); } else { if( pLeader->IsNearPC( pMember ) ) pMember->AddHdr( pMember->GetId(), SNAPSHOTTYPE_PARTYSKILL_RETREAT ); } } } } break; case ST_SPHERECIRCLE: { // 크리티컬 확률 CUser *pLeader = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeader ) == FALSE ) break; if( pLeader->m_idSetTarget != NULL_ID ) { CMover * pT = prj.GetMover( pLeader->m_idSetTarget ); if( pT && !pT->IsPlayer() ) { g_DPCoreClient.SendRemovePartyPoint( uPartyId, pItemProp->dwExp ); for( i = 0; i < m_nSizeofMember; i ++ ) { pMember = g_UserMng.GetUserByPlayerID( m_aMember[i].m_uPlayerId ); if( IsValidObj( (CObj*)pMember ) ) { if( m_nModeTime[PARTY_GIFTBOX_MODE] || m_nModeTime[PARTY_FORTUNECIRCLE_MODE] ) { pMember->AddHdr( pLeader->m_idSetTarget, SNAPSHOTTYPE_PARTYSKILL_SPHERECIRCLE ); pMember->m_dwFlag |= MVRF_CRITICAL; } else { if( pLeader->IsNearPC( pMember ) ) { pMember->AddHdr( pLeader->m_idSetTarget, SNAPSHOTTYPE_PARTYSKILL_SPHERECIRCLE ); pMember->m_dwFlag |= MVRF_CRITICAL; } } } } } else { pLeader->AddSendErrorParty( ERROR_NOTTARGET, ST_SPHERECIRCLE ); // 타겟이 몬스터가 아니다 } } else { pLeader->AddSendErrorParty( ERROR_NOTTARGET, ST_SPHERECIRCLE ); // 타겟을 안잡았다. } // g_DPCoreClient.SendSetPartyExp( uLeaderid, m_nPoint ); } break; #if __VER >= 12 // __JHMA_VER12_1 //12차 극단유료아이템 case ST_LINKATTACK: { // 데미지 증가 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_LINKATTACK_MODE, dwSkillTime, nRemovePoint, nHasCashSkill ); } break; case ST_FORTUNECIRCLE: { // 유니크 아이템 발생확률 증가 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_FORTUNECIRCLE_MODE, dwSkillTime, nRemovePoint, nHasCashSkill ); } break; case ST_STRETCHING: { // 쉬는경우 회복속도 높여줌 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_STRETCHING_MODE, dwSkillTime, nRemovePoint, nHasCashSkill ); } break; case ST_GIFTBOX: { // 아이템 양이 두배 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_GIFTBOX_MODE, dwSkillTime, nRemovePoint, nHasCashSkill ); } break; #else //12차 극단유료아이템 case ST_LINKATTACK: { // 데미지 증가 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_LINKATTACK_MODE, dwSkillTime, nRemovePoint ); } break; case ST_FORTUNECIRCLE: { // 유니크 아이템 발생확률 증가 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_FORTUNECIRCLE_MODE, dwSkillTime, nRemovePoint ); } break; case ST_STRETCHING: { // 쉬는경우 회복속도 높여줌 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_STRETCHING_MODE, dwSkillTime, nRemovePoint ); } break; case ST_GIFTBOX: { // 아이템 양이 두배 g_DPCoreClient.SendUserPartySkill( uLeaderid, PARTY_GIFTBOX_MODE, dwSkillTime, nRemovePoint ); } break; #endif // //12차 극단유료아이템 default: break; } } #ifndef __PARTYDEBUG else { CUser *pLeader = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeader ) ) { pLeader->AddSendErrorParty( ERROR_NOTPARTYPOINT ); } //포인트가 모자라 스킬을사용할수 없습니다. } #endif // __PARTYDEBUG } #ifndef __PARTYDEBUG else { CUser *pLeader = g_UserMng.GetUserByPlayerID( m_aMember[0].m_uPlayerId ); // 리더의 포인터 if( IsValidObj( pLeader ) ) { pLeader->AddSendErrorParty( ERROR_NOTPARTYSKILL ); } //이 스킬은 배우지를 못했습니다. } #endif // __PARTYDEBUG } } else { // 리더가 아니거나 순회극단이 아닌경우 } #endif // __WORLDSERVER }
// 공격 대상을 찾아서 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; }
void CWndPartyCtrl::OnDraw( C2DRender* p2DRender ) { if( NULL == g_pPlayer ) return; CPoint pt( 3, 3 ); // pt.y -= ( m_nFontHeight + 3 ) * m_wndScrollBar.GetScrollPos(); #if __VER < 11 // __CSC_VER11_4 CWndMessenger* pWndMessenger = (CWndMessenger*)GetWndBase( APP_MESSENGER_ ); #endif //__CSC_VER11_4 CWndWorld* pWndWorld = (CWndWorld*)g_WndMng.GetWndBase( APP_WORLD ); int nMax = g_Party.m_nSizeofMember; // 눈에 보이는 갯수가 페이지라인수 보다 크면 보이는 갯수를 페이지라인수로 조정 if( nMax - m_wndScrollBar.GetScrollPos() > m_wndScrollBar.GetScrollPage() ) nMax = m_wndScrollBar.GetScrollPage() + m_wndScrollBar.GetScrollPos(); if( nMax < m_wndScrollBar.GetScrollPos() ) nMax = 0; TEXTUREVERTEX2* pVertex = new TEXTUREVERTEX2[ 6 * 2 * nMax ]; TEXTUREVERTEX2* pVertices = pVertex; for( int i = m_wndScrollBar.GetScrollPos(); i < nMax; i++ ) { CMover* pObjMember = prj.GetUserByID( g_Party.m_aMember[i].m_uPlayerId ); CString strMember; #if __VER >= 11 // __SYS_PLAYER_DATA PlayerData* pPlayerData = CPlayerDataCenter::GetInstance()->GetPlayerData( g_Party.m_aMember[i].m_uPlayerId ); int nJob = pPlayerData->data.nJob; int nSex = pPlayerData->data.nSex; #else // __SYS_PLAYER_DATA int nJob = g_Party.m_aMember[ i ].m_nJob; int nSex = g_Party.m_aMember[ i ].m_nSex; #endif // __SYS_PLAYER_DATA // 상태에 따라 색 변경 DWORD dwColor = 0xff000000; if( IsValidObj(pObjMember) ) { if( pObjMember->GetHitPoint() == 0 ) dwColor = 0xffff0000; // 죽은놈 else if( ((FLOAT)pObjMember->GetHitPoint()) / ((FLOAT)pObjMember->GetMaxHitPoint()) < 0.1f ) dwColor = 0xffffff00; // HP 10% 이하인 놈 strMember.Format( "%d %s", pObjMember->GetLevel(), pObjMember->GetName() ); } else { dwColor = 0xff878787; // 디폴트는 주위에 없는 놈 if( g_Party.m_aMember[ i ].m_bRemove ) dwColor = 0xff000000; // 서버에 없는 놈 #if __VER >= 11 // __SYS_PLAYER_DATA strMember.Format( "?? %s", pPlayerData->szPlayer ); #else // __SYS_PLAYER_DATA strMember.Format( "?? %s", g_Party.m_aMember[ i ].m_szName ); #endif // __SYS_PLAYER_DATA } if( i == m_nCurSelect ) dwColor = 0xff6060ff; int x = 0, nWidth = m_rectClient.Width() - 10;// - 1; CRect rect( x, pt.y, x + nWidth, pt.y + m_nFontHeight ); rect.SetRect( x + 20, pt.y + 18, x + nWidth - 10, pt.y + 30 ); nWidth = pObjMember ? pObjMember->GetHitPointPercent( rect.Width() ) : 0; CRect rectTemp = rect; rectTemp.right = rectTemp.left + nWidth; if( rect.right < rectTemp.right ) rectTemp.right = rect.right; m_pTheme->RenderGauge( p2DRender, &rect, 0xffffffff, m_pVBGauge, &m_texGauEmptyNormal ); m_pTheme->RenderGauge( p2DRender, &rectTemp, 0x64ff0000, m_pVBGauge, &m_texGauFillNormal ); rect.SetRect( x + 3, pt.y, x + 3 + 32, pt.y + 6 + 32 ); p2DRender->TextOut( x + 20, pt.y + 3, strMember, dwColor ); if( MAX_EXPERT <= nJob ) { #if __VER >= 10 // __LEGEND if( MAX_PROFESSIONAL <= nJob && nJob < MAX_MASTER ) pWndWorld->m_texMsgIcon.MakeVertex( p2DRender, CPoint( 2, pt.y ), ( 70 + nJob - 16 ) + ( 8 * nSex ), &pVertices, 0xffffffff ); else if( MAX_MASTER <= nJob ) pWndWorld->m_texMsgIcon.MakeVertex( p2DRender, CPoint( 2, pt.y ), ( 70 + nJob - 24 ) + ( 8 * nSex ), &pVertices, 0xffffffff ); else #endif //__LEGEND pWndWorld->m_texMsgIcon.MakeVertex( p2DRender, CPoint( 2, pt.y ), ( 70 + nJob - 6 ) + ( 8 * nSex ), &pVertices, 0xffffffff ); } else { pWndWorld->m_texMsgIcon.MakeVertex( p2DRender, CPoint( 2, pt.y ), 12 + nJob + ( 6 * nSex ), &pVertices, 0xffffffff ); } pt.y += m_nFontHeight + 3; } pWndWorld->m_texMsgIcon.Render( m_pApp->m_pd3dDevice, pVertex, ( (int) pVertices - (int) pVertex ) / sizeof( TEXTUREVERTEX2 ) ); safe_delete_array( pVertex ); }
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; }
// // 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; }
// 참가자 구성 void CGuildCombat1to1Mng::SetMemberLineUp( CUser* pUser, vector<u_long>& vecMemberId ) { if( m_nState != GC1TO1_OPEN ) // 참가자 구성 시간이 아니다. { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_NOLINEUP ); return; } int nIndex = GetTenderGuildIndexByUser( pUser ); if( nIndex == NULL_ID ) // 입찰되지 않았거나 순위에서 밀린 길드 { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_CANNOT_MAKEUP ); return; } if( (int)( vecMemberId.size() ) < m_nMinJoinPlayer ) // 최소 참가자 수보다 적다. { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_LOWMINPLAYER, "%d", m_nMinJoinPlayer ); return; } if( (int)( vecMemberId.size() ) > m_nMaxJoinPlayer ) { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_OVERMAXPLAYER, "%d", m_nMaxJoinPlayer ); return; } // 길드마스터 또는 킹핀급만 가능 CGuild* pGuild = pUser->GetGuild(); if( pGuild ) { CGuildMember* pGuildMember = pGuild->GetMember( pUser->m_idPlayer ); if( pGuildMember ) { if( pGuildMember->m_nMemberLv != GUD_MASTER && pGuildMember->m_nMemberLv != GUD_KINGPIN ) { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_NOLINEUPAUTH ); return; } } } BOOL bMasterOrKingpin = FALSE; // 최소 참가 레벨 검사 for( int i=0; i<(int)( vecMemberId.size() ); i++ ) { CUser* pUserTemp = (CUser*)prj.GetUserByID( vecMemberId[i] ); if( IsValidObj( pUserTemp ) && pUserTemp->GetLevel() < m_nMinJoinPlayerLevel ) { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_LIMIT_LEVEL_NOTICE ); return; } if( IsValidObj( pUserTemp ) && !bMasterOrKingpin ) { CGuildMember* pGuildMember = pGuild->GetMember( pUserTemp->m_idPlayer ); if( pGuildMember ) if( pGuildMember->m_nMemberLv == GUD_MASTER || pGuildMember->m_nMemberLv == GUD_KINGPIN ) bMasterOrKingpin = TRUE; } } if( !bMasterOrKingpin ) { pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_HAVENOT_MASTER ); return; } m_vecTenderGuild[nIndex].vecMemberId.clear(); m_vecTenderGuild[nIndex].vecMemberId = vecMemberId; pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_LINEUPCOMPLETE ); g_dpDBClient.SendGC1to1LineUp( m_vecTenderGuild[nIndex].ulGuildId, vecMemberId ); }
// 1대1 길드대전 오픈 void CGuildCombat1to1Mng::GuildCombat1to1Open( BOOL bGMText ) { if( !g_eLocal.GetState( EVE_GUILDCOMBAT1TO1 ) ) return; vector<__GC1TO1TENDER>::iterator it; if( !bGMText ) { for( it=m_vecTenderFailGuild.begin(); it!=m_vecTenderFailGuild.end(); it++ ) { // 이전 1:1길드대전에 입찰 실패 길드가 신청금을 수령하지 않았을 경우 g_dpDBClient.SendGC1to1Tender( 'U', (*it).ulGuildId, (*it).nPenya, 'N' ); } m_vecTenderFailGuild.clear(); } // 신청한 길드수가 최소 참여 길드수보다 적을 때 if( (int)( m_vecTenderGuild.size() ) < m_nMinJoinGuild ) { // 1대1 길드대전 취소 및 연장 처리 CString strTemp; strTemp.Format( prj.GetText( TID_GAME_GUILDCOMBAT1TO1_NOGAME ), m_nMinJoinGuild ); g_DPCoreClient.SendCaption( strTemp ); ClearTime(); m_nState = GC1TO1_CLOSE; return; } // 1:1길드대전 오픈 메세지.. g_DPCoreClient.SendCaption( prj.GetText( TID_GAME_GUILDCOMBAT1TO1_OPEN ) ); g_DPCoreClient.SendCaption( prj.GetText( TID_GAME_GUILDCOMBAT1TO1_LINEUP ) ); // 참가자 구성 시간 설정 m_nState = GC1TO1_OPEN; m_nWaitTime = (int)m_Lua.GetGlobalNumber( "MemberLineUpTime" ); m_dwTime = GetTickCount(); // 입찰 순위에 들지 못한 길드 제거 int nCount = 0; for( it=m_vecTenderGuild.begin(); it!=m_vecTenderGuild.end(); ) { nCount++; if( nCount <= m_nMaxJoinGuild ) it++; else // 입찰 순위에서 밀려난 경우 { CGuild* pGuild = g_GuildMng.GetGuild( (*it).ulGuildId ); if( pGuild ) { CUser* pUser = (CUser*)prj.GetUserByID( pGuild->m_idMaster ); if( IsValidObj( pUser ) ) pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_FAILTENDER ); } g_dpDBClient.SendGC1to1Tender( 'U', (*it).ulGuildId, (*it).nPenya, 'F' ); m_vecTenderFailGuild.push_back( (*it) ); it = m_vecTenderGuild.erase( it ); } } // 입찰 순위에는 들어갔지만 상대 길드가 없는 경우(홀수) if( m_vecTenderGuild.size() % 2 != 0 ) { it = m_vecTenderGuild.end(); it--; // 마지막 순위 // 노트 : rbegin()을 사용하시오. CGuild* pGuild = g_GuildMng.GetGuild( (*it).ulGuildId ); if( pGuild ) { CUser* pUser = (CUser*)prj.GetUserByID( pGuild->m_idMaster ); if( IsValidObj( pUser ) ) pUser->AddDefinedText( TID_GAME_GUILDCOMBAT1TO1_FAILTENDER ); } g_dpDBClient.SendGC1to1Tender( 'U', (*it).ulGuildId, (*it).nPenya, 'F' ); m_vecTenderFailGuild.push_back( (*it) ); m_vecTenderGuild.erase( it ); } // 출전 가능한 길드의 모든 길드원에게 OPEN STATE 알림(길드 마스터는 참가자 구성 시간 출력) for( it=m_vecTenderGuild.begin(); it!=m_vecTenderGuild.end(); it++ ) { CGuild* pGuild = g_GuildMng.GetGuild( (*it).ulGuildId ); if( pGuild ) { for( map<u_long, CGuildMember*>::iterator it2=pGuild->m_mapPMember.begin(); it2!=pGuild->m_mapPMember.end(); it2++ ) { CUser* pUser = (CUser*)prj.GetUserByID( it2->first ); if( IsValidObj( pUser ) ) SendNowState( pUser ); } } } g_dpDBClient.SendGC1to1StateToDBSrvr(); // 1:1길드대전이 오픈되었다고 DBServer에 알림 }
// // 외부에서 UseSkill을 명령할땐 이것으로 호출하자. // sutType : 스킬을 사용할때 스킬큐에서 연타로 사용한건가 일반적인 사용을 한건가.c // int CMover::CMD_SetUseSkill( OBJID idTarget, int nSkillIdx, SKILLUSETYPE sutType ) { m_oaCmd = OBJACT_NONE; TRACE( "CMD_SetUseSkill( " ); if( m_pActMover->IsFly() ) return 0; // 비행중엔 스킬사용 금지. if( m_pActMover->IsActAttack() ) return 0; if( m_pActMover->IsActJump() ) return 0; // 점프중엔 사용금지. if( m_pActMover->GetState() & OBJSTA_DMG_FLY_ALL ) return 0; // 데미지 플라이중엔 스킬사용금지. if( IsDie() ) return 0; // 죽었을때 사용금지. LPSKILL pSkill = GetSkill( 0, nSkillIdx ); // this가 가진 스킬중 nIdx에 해당하는 스킬을 꺼낸다. if( pSkill == NULL ) { Error( "CMD_SetUseSkill : %s skill(%d) not found", m_szName, nSkillIdx ); return 0; // } ItemProp* pSkillProp = pSkill->GetProp(); if( pSkillProp == NULL ) // JobSkill 리스트에서 꺼낸 스킬의 프로퍼티를 꺼냄. { Error( "CMD_SetUseSkill : %s. skill(%d) property not found", m_szName, pSkill->dwSkill ); return 0; // } if( IsPlayer() && IsStateMode( STATE_BASEMOTION_MODE ) ) // 시전중(준비시간)일땐 사용금지. { #ifdef __CLIENT g_DPlay.SendStateModeCancel( STATE_BASEMOTION_MODE, STATEMODE_BASEMOTION_CANCEL ); #endif return 0; } // 도달범위 - 얼마나 가까이 근접해야하는가. 미터단위 float fArrivalRange = 0.0f; fArrivalRange = GetAttackRange( pSkillProp->dwAttackRange ); switch( pSkillProp->dwUseChance ) { case WUI_NOW: // 타겟팅과 상관없이 자기자신에게 쓰는 방식. idTarget = GetId(); break; case WUI_TARGETINGOBJ: // 셀렉트 되어 있는 타겟에게 사용. { #ifdef __CLIENT CObj *pFocusObj = GetWorld()->GetObjFocus(); if( pFocusObj && pFocusObj->GetType() == OT_MOVER ) idTarget = ((CMover*)pFocusObj)->GetId(); #else if( IsPlayer() ) idTarget = ((CUser *)this)->m_idSetTarget; #endif // __CLIENT } break; #ifdef __CLIENT case WUI_TARGETCURSORPTZ: { idTarget = GetId(); CRect rect; D3DXVECTOR3 vPos; CWndWorld* pWndWorld; pWndWorld = (CWndWorld*)g_WndMng.GetWndBase( APP_WORLD ); rect = pWndWorld->GetClientRect(); if( GetWorld()->ClientPointToVector( NULL, rect, pWndWorld->GetMousePoint(), &GetWorld()->m_matProj, &GetWorld()->GetCamera()->m_matView, &vPos, TRUE ) ) { #ifdef __SKILL0517 AddSkillProp* pAddSkillProp = prj.GetAddSkillProp( pSkillProp->dwSubDefine, GetSkillLevel( pSkill ) ); // UseSkill에서 사용한 스킬의 프로퍼티 꺼냄 #else // __SKILL0517 AddSkillProp* pAddSkillProp = prj.GetAddSkillProp( pSkillProp->dwSubDefine, pSkill->dwLevel ); // UseSkill에서 사용한 스킬의 프로퍼티 꺼냄 #endif // __SKILL0517 if( pAddSkillProp == NULL ) { Error( "CMover::OnMagicSkill : %s. add스킬(%d)의 프로퍼티가 없다.", m_szName, nSkillIdx ); return 0; // property not found } FLOAT fDist; FLOAT fMaxDistSq; D3DXVECTOR3 vDist; fMaxDistSq = (float)pAddSkillProp->dwSkillRange; fMaxDistSq *= fMaxDistSq; vDist = vPos - GetPos(); fDist = D3DXVec3LengthSq( &vDist ); SetAngle( GetDegree(vPos, GetPos()) ); // 목표쪽으로 몸을 돌림. // 텔레포트 할 위치가 멀경우 현제 스킬에 해당하는 거리로 바꿔준다 if( fDist > fMaxDistSq ) { FLOAT fLength; D3DXVECTOR3 vDirNor; D3DXVec3Normalize( &vDirNor, &vDist ); fLength = (float)pAddSkillProp->dwSkillRange; float y = vPos.y; vPos = GetPos() + (vDirNor * fLength); vPos.y = y; // 스킬에 해당하는 거리로 바꾼곳이 못가는 지역이라면 갈수 있는 지역을 검사한다. int nAttr = GetWorld()->GetHeightAttribute( vPos.x, vPos.z ); if( nAttr != HATTR_NONE ) { while( nAttr != HATTR_NONE ) { if( nAttr == HATTR_NOFLY ) break; fLength -= 1.0f; // 1미터씩 줄여가며 계산한다. vPos = GetPos() + (vDirNor * fLength); nAttr = GetWorld()->GetHeightAttribute( vPos.x, vPos.z ); // 캐릭터의 앞 뒤로 이동불가 일 경우 뒷쪽이 이동불가 해제 될때 까지 계속 계산하여 이동시킴 // 그러므로 텔레포트 스킬 범위를 넘어설 경우 원래 자리로 텔레포트 하도록 처리 D3DXVECTOR3 vTemp = vPos - GetPos(); float fTemp = D3DXVec3LengthSq( &vTemp ); if(fTemp > fMaxDistSq) { vPos = GetPos(); break; } } // 한번더 줄여줌 fLength -= 1.0f; vPos = GetPos() + (vDirNor * fLength); // 줄인 곳이 이동불가 지역일 수 있다. nAttr = GetWorld()->GetHeightAttribute( vPos.x, vPos.z ); if( nAttr != HATTR_NONE ) { vPos = GetPos(); } } } else // 텔레포트 할 위치가 해당스킬 거리보다 작을경우 { int nAttr = GetWorld()->GetHeightAttribute( vPos.x, vPos.z ); FLOAT fLength; D3DXVECTOR3 vDirNor; D3DXVec3Normalize( &vDirNor, &vDist ); fLength = 0.0f; while( nAttr != HATTR_NONE ) { if( nAttr == HATTR_NOFLY ) break; fLength -= 1.0f; vPos = GetPos() + (vDirNor * fLength); nAttr = GetWorld()->GetHeightAttribute( vPos.x, vPos.z ); // 캐릭터의 앞 뒤로 이동불가 일 경우 뒷쪽이 이동불가 해제 될때 까지 계속 계산하여 이동시킴 // 그러므로 텔레포트 스킬 범위를 넘어설 경우 원래 자리로 텔레포트 하도록 처리 D3DXVECTOR3 vTemp = vPos - GetPos(); float fTemp = D3DXVec3LengthSq( &vTemp ); if(fTemp > fMaxDistSq) { vPos = GetPos(); break; } } } if( IsActiveMover() && g_eLocal.GetState( EVE_SCHOOL ) ) // 학교이벤섭이면. { D3DXVECTOR3 v1, v2; v1 = GetPos(); v1.y += 0.1f; v2 = vPos; v2.y += 0.1f; if( GetWorld()->IntersectObjLine( NULL, v1, v2, FALSE, FALSE ) ) // 텔레포트는 라인체크함. { g_WndMng.PutString( prj.GetText(TID_GAME_NOMOVING), NULL, prj.GetTextColor(TID_GAME_NOMOVING) ); g_WndMng.m_pWndWorld->SetNextSkill( NEXTSKILL_NONE ); return 0; } } pWndWorld->m_vTelePos = vPos; } else { g_WndMng.m_pWndWorld->SetNextSkill( NEXTSKILL_NONE ); g_WndMng.PutString( prj.GetText(TID_GAME_NOMOVING), NULL, prj.GetTextColor(TID_GAME_NOMOVING) ); return 0; } } break; #endif // __CLIENT } // 타인에게 쓰는경우에만 검사... if( idTarget != GetId() ) { CMover *pTarget = prj.GetMover( idTarget ); if( IsValidObj(pTarget) ) { if( pSkillProp->nEvildoing < 0 ) // 나쁜 스킬은 if( IsAttackAble(pTarget) == FALSE ) // 공격허용이 되지 않으면 사용할 수 없음. return 0; if( pSkill->dwSkill == SI_ASS_HEAL_RESURRECTION ) // 부활을 사용했을때 { if( pTarget->IsNPC() || pTarget->IsDie() == FALSE ) // 상대가 NPC거나 상대가 죽어있지 않다면 취소 return 0; } else { if( pTarget->IsDie() ) // 부활이 아닌 스킬을 사용했을때 상대가 죽어있으면 사용안됨. return 0; } } } // 타겟 근접 방식. switch( pSkillProp->dwExeTarget ) { case EXT_SELFCHGPARAMET: // 시전자 자신에게 사용하는 종류 idTarget = GetId(); // 타겟을 자기자신으로 설정. SetDestObj( idTarget, fArrivalRange, TRUE ); // 이동할 목표물을 idTarget으로 설정. << 이게 왜 필요하지? ㅡ.ㅡ? break; case EXT_MAGICATKSHOT: case EXT_MAGICATK: // 원거리에서 마법으로 타겟을 공격 case EXT_MAGICSHOT: if( idTarget == NULL_ID ) return 0; // 타겟이 없거나 유효하지 않으면 실패. SetDestObj( idTarget, fArrivalRange, TRUE ); // 이동할 목표물을 idTarget으로 설정. 다가가는 범위는 fArrivalRange값으로.. break; case EXT_ANOTHERWITH: // 나 혹은 다른사람에게 시전 if( idTarget == NULL_ID ) // 타겟이 잡혀있지 않으면 idTarget = GetId(); // 자신을 타겟으로 잡음 SetDestObj( idTarget, fArrivalRange, TRUE ); // 이동할 목표물을 idTarget으로 설정. break; case EXT_AROUNDATK: // 내 주위적들을 대상. idTarget = GetId(); // 타겟을 자기자신으로 설정. SetDestObj( idTarget, fArrivalRange, TRUE ); // 이동할 목표물을 idTarget으로 설정. break; case EXT_OBJCHGPARAMET: // 타인에게 사용 default: // 그외는 모두 근접하자. if( idTarget == NULL_ID ) return 0; // 타겟이 없거나 유효하지 않으면 실패. SetDestObj( idTarget, fArrivalRange, TRUE ); // 이동할 목표물을 idTarget으로 설정. break; } ClearActParam(); SetCmd( OBJACT_USESKILL, nSkillIdx, idTarget, sutType ); // 사정거리가 되었을때 실행할 명령 셋팅. TRACE( "\n)CMD_SetUseSkill\n" ); return 1; }