//1表示增益 //2表示减益 BOOL CPKSys::JudgeAttackRelation(CMoveShape *pAttacker,CMoveShape *pBeenAttacker,int nAddSub) { if (pBeenAttacker->IsGod()) { //((CPlayer*)pAttacker)->SendNotifyMessage(AppFrame::GetText("STR_WS_SKILL_FIFTEENTH"),0xffff0000,0,eNOTIFYPOS_CENTER); return FALSE; } if (!IsAttackAble(pAttacker,pBeenAttacker)) { return FALSE; } CServerRegion* pRegion = dynamic_cast<CServerRegion*>( pAttacker->GetFather() ); if( !pRegion ) return FALSE; //PVP if (pAttacker->GetType()==TYPE_PLAYER && pBeenAttacker->GetType()==TYPE_PLAYER && nAddSub==2) { CPlayer* pPlayerAttacker = dynamic_cast<CPlayer*>( pAttacker ); CPlayer* pPlayerBeenAttacker = dynamic_cast<CPlayer*>( pBeenAttacker ); // 如果在nopk场景,玩家不能PK的 if(0 == pRegion->IsNoPk()) return FALSE; CRegion::eSecurity eBSecurityType = pRegion->GetSecurity(pPlayerBeenAttacker->GetTileX(),pPlayerBeenAttacker->GetTileY()); CRegion::eSecurity eSecurityType = pRegion->GetSecurity(pPlayerAttacker->GetTileX(),pPlayerAttacker->GetTileY()); if (eSecurityType == CRegion::SECURTIY_SAFE || eBSecurityType == CRegion::SECURTIY_SAFE) { return FALSE; } //组队 if (pPlayerAttacker->IsPk_Team()) { if (pPlayerAttacker->GetTeamID()!=NULL_GUID && pPlayerAttacker->GetTeamID()==pPlayerBeenAttacker->GetTeamID()) { return FALSE; } } //帮会 if (pPlayerAttacker->IsPk_Union()) { if (pPlayerAttacker->GetFactionID()!=NULL_GUID && pPlayerAttacker->GetFactionID()==pPlayerBeenAttacker->GetFactionID()) { return FALSE; } } //本国 if (pPlayerAttacker->IsPk_Country()) { // [9/7/2009 chenxianj] //只保护本国白名玩家 if (pPlayerAttacker->GetCountry()==pPlayerBeenAttacker->GetCountry() && pPlayerBeenAttacker->GetPkValue()==0) { return FALSE; } } //阵营 if (pPlayerAttacker->IsPk_Camp()) { // [9/7/2009 chenxianj] //只保护本阵营白名玩家 if (IsSameCamp(pPlayerAttacker,pPlayerBeenAttacker) && pPlayerBeenAttacker->GetPkValue()==0) { return FALSE; } } //全体 if (pPlayerAttacker->IsPk_Normal()) { if(!IsSameCamp(pPlayerAttacker,pPlayerBeenAttacker) && pPlayerBeenAttacker->GetPkValue()==0 && pPlayerBeenAttacker->GetPVPValue()==0) { return FALSE; } } //红名 if (pPlayerAttacker->IsPk_Badman()) { if (pPlayerBeenAttacker->GetPkValue()>0) { return FALSE; } } //海盗 if ( pPlayerAttacker->IsPk_Pirate()) { if (pPlayerBeenAttacker->GetPVPValue()>0) { return FALSE; } } } //PVM if (pAttacker->GetType()==TYPE_PLAYER && pBeenAttacker->GetType()==TYPE_MONSTER) { CPlayer* pPlayerAttacker = dynamic_cast<CPlayer*>( pAttacker ); CMonster* pPlayerBeenAttacker = dynamic_cast<CMonster*>( pBeenAttacker ); CRegion::eSecurity SecurityType = pRegion->GetSecurity(pPlayerBeenAttacker->GetTileX(),pPlayerBeenAttacker->GetTileY()); if (SecurityType == CRegion::SECURTIY_SAFE && nAddSub==1) { //人对怪在安全区不能使用增益技能 return FALSE; } if (((CMonster*)pBeenAttacker)->GetNpcType()==NT_Guard) { //国家 if (pPlayerAttacker->IsPk_Country()) { if (pAttacker->GetCountry()==pBeenAttacker->GetCountry()) { return FALSE; } } //阵营 if (pPlayerAttacker->IsPk_Camp()) { if (IsSameCamp(pPlayerAttacker,pPlayerBeenAttacker)) { return FALSE; } } //全体 if (pPlayerAttacker->IsPk_Normal()) { return FALSE; } } } //MVP if (pAttacker->GetType()==TYPE_MONSTER && pBeenAttacker->GetType()==TYPE_PLAYER) { CMonster* pPlayerAttacker = dynamic_cast<CMonster*>( pAttacker ); CPlayer* pPlayerBeenAttacker = dynamic_cast<CPlayer*>( pBeenAttacker ); CRegion::eSecurity SecurityType = pRegion->GetSecurity(pPlayerBeenAttacker->GetTileX(),pPlayerBeenAttacker->GetTileY()); if (SecurityType == CRegion::SECURTIY_SAFE && nAddSub==1) { //怪对人在安全区不能使用增益技能 return FALSE; } } return TRUE; }
// // 외부에서 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; }