void do_Attack(CPC* pc, CNetMsg::SP& msg) { CDratanCastle * pCastle = CDratanCastle::CreateInstance(); pCastle->CheckRespond(pc); RequestClient::doAttack* packet = reinterpret_cast<RequestClient::doAttack*>(msg->m_buf); // 동시 공격은 최대 5 if (packet->multicount > 5) { LOG_ERROR("HACKING : invalid multi count[%d]. charIndex[%d]", packet->multicount, pc->m_index); pc->m_desc->Close("invalid multi count"); return; } // multi target의 중복 검사 if (packet->multicount > 1) { std::set<int> tset; for (int i = 0; i < packet->multicount; ++i) { if (tset.insert(packet->list[i].index).second == false) { LOG_ERROR("HACKING : duplicate multi target[%d]. charIndex[%d]", packet->list[i].index, pc->m_index); pc->m_desc->Close("duplicate multi target"); return; } } } // 대상 검색 : 인접 셀에서만 CArea* area = pc->m_pArea; if (area == NULL) return; CCharacter* ch = area->FindCharInCell(pc, packet->aIndex, (MSG_CHAR_TYPE)packet->aCharType); if (ch == NULL) return; CCharacter* tch = area->FindCharInCell(ch, packet->tIndex, (MSG_CHAR_TYPE)packet->tCharType); if (tch == NULL) return; // 공격자가 PC이면 자신의 캐릭만 조정 if (IS_PC(ch) && ch != pc) return ; switch (ch->m_type) { case MSG_CHAR_PC: { if( IS_NPC(tch)) { CPC * pPC = TO_PC(ch); CNPC * pNPC = TO_NPC(tch); if( pPC->GetSummonNpc(SUMMON_NPC_TYPE_MERCENARY) == pNPC ) return; } //pvp보호 아이템 체크 if (checkPvPProtect(pc, tch) == false) return; // 공격 거리 검사 if (GetDistance(ch, tch) > ch->m_attackRange * 2) return ; // 공속 검사 if ( ch->ChekAttackType() && ch->CheckHackAttack(pc)) return ; // 펫 타고 있으면 불가능 if (pc->GetPet() && pc->GetPet()->IsMount()) return ; // 공성 아이템 착용시 해당 스킬 발동 int mixSkillIndex[] = { pc->m_opSturnIndex, pc->m_opBloodIndex, pc->m_opPoisonIndex, pc->m_opSlowIndex, pc->m_opMoveIndex }; int mixSkillLevel[] = { pc->m_opSturnLevel, pc->m_opBloodLevel, pc->m_opPoisonLevel, pc->m_opSlowLevel, pc->m_opMoveLevel }; CSkill* skillMixItem = NULL; int i; int bStop = 0; for (i = 0; i < 5; i++) { if (mixSkillIndex[i] > 0 && mixSkillLevel[i] > 0) { skillMixItem = gserver->m_skillProtoList.Create(mixSkillIndex[i], mixSkillLevel[i]); if (skillMixItem) { bool bApply; bStop = ApplySkill(ch, tch, skillMixItem, -1, bApply); } delete skillMixItem; skillMixItem = NULL; if (bStop != 0) return ; } } if (IS_PC(ch)) { CPC* pPCAttacker = TO_PC(ch); CItem* weaponItem = pPCAttacker->m_wearInventory.wearItemInfo[WEARING_WEAPON]; // 암흑 공격 if (pPCAttacker->m_opAttackBlind > 0) { CSkill* pSkillBlind = gserver->m_skillProtoList.Create(415, pPCAttacker->m_opAttackBlind); int nRetApplySkill = 0; if (pSkillBlind) { bool bApply; nRetApplySkill = ApplySkill(ch, tch, pSkillBlind, -1, bApply); } delete pSkillBlind; pSkillBlind = NULL; if (nRetApplySkill != 0) return ; } // 독 공격 if (pPCAttacker->m_opAttackPoison > 0) { CSkill* pSkillPoison = gserver->m_skillProtoList.Create(414, pPCAttacker->m_opAttackPoison); int nRetApplySkill = 0; if (pSkillPoison) { bool bApply; nRetApplySkill = ApplySkill(ch, tch, pSkillPoison, -1, bApply); } delete pSkillPoison; pSkillPoison = NULL; if (nRetApplySkill != 0) return ; } } } // PC 검사 break; case MSG_CHAR_PET: case MSG_CHAR_ELEMENTAL: // TODO : 소환수 공속 검사 // 공격 거리 검사 if (GetDistance(ch, tch) > ch->m_attackRange * 2) return ; // 공속 검사 if (ch->CheckHackAttack(pc)) return ; break; default: break; } if(IS_PC(tch)) { if( TO_PC(tch)->m_bImmortal == true ) return; } if (DEAD(ch) || !ch->CanAttack() || pc->IsDisable()) return ; // 결계걸린 대상은 공격 못한다. if ( tch->m_assist.m_state & AST_FREEZE ) return; //무적 버프 대상은 공격할 수 없다. if ( tch->m_assist.m_state & AST_SAFEGUARD ) { CNetMsg::SP rmsg(new CNetMsg); SysMsg(rmsg, MSG_SYS_DO_NOT_ATTACK_IMMOTAL); SEND_Q(rmsg, pc->m_desc); return; } // 대상이 NPC일때만 멀티 공격 if (!IS_NPC(tch)) packet->multicount = 0; // 최소한 공격 1회 이상 bool bAttacked = false; bool bAttackedPet = false; // 애완동물은 NPC상대시 레벨 검사 // 멀티 공격 검사용 std::set<int> listMultiTarget; while (tch) { bool bBlocked = false; // NPC를 공격할 때에만 속성맵 검사 (프리PK 지역이 아닐때만) if ( IS_NPC(tch) && !(tch->GetMapAttr() & MATT_FREEPKZONE) ) { char tempy = GET_YLAYER(ch); bBlocked = (!area->IsNotBlocked(ch, tch, true, tempy)); } int ret = 0; if (!bBlocked) { if (IS_PC(ch) && ch->IsEnemy(tch)) { bAttacked = true; #ifdef MONSTER_AI if (tch != NULL && IS_NPC(tch)) { CNPC * pTemp = TO_NPC(tch); if (pTemp != NULL) { if (ch->m_level - tch->m_level <= 5 && pTemp->m_proto->m_index != 303 /*악마의 묘지*/) { bAttackedPet = true; } if (pTemp->m_bMoveLock || pTemp->m_bMoveToRegen) { pTemp->m_bMoveToRegen = false; pTemp->m_bMoveLock = false; pTemp->m_pulseMoveLock = 0; pTemp->m_postregendelay = 0; } } } #else if (tch != NULL && IS_NPC(tch) && ch->m_level - tch->m_level <= 5) { CNPC * pTemp = TO_NPC(tch); if (pTemp != NULL && pTemp->m_proto->m_index != 303 /*악마의 묘지*/) { bAttackedPet = true; } } #endif } listMultiTarget.insert(tch->m_index); ret = ProcAttack(ch, tch, ch->GetAttackType(NULL), NULL, 0); } if (ret == -1 || tch->m_index == -1) // ProcAttack()안에서 Character 객체가 소멸된 경우도 포함 { tch = NULL; continue ; } //공격 발동형 스킬 추가 if( pc->m_optionAttSkillList.count() > 0 ) { //공격 할 시에 적에게 스킬 적용 void* pos = pc->m_optionAttSkillList.GetHeadPosition(); bool bApply = false; while (pos) { CSkill* skill = pc->m_passiveSkillList.GetNext(pos); if (skill && skill->m_proto) { int rand = GetRandom(1, 10000); if( rand < skill->m_optionSkillProb ) { ApplySkill(ch, tch, skill, -1, bApply); if(bApply == false) { GAMELOG << init("EVENT_PCBANG_2NDS SKILL FAILED (LOGIN) ", pc ) << end;// 스킬 적용 실패 } } } } } if (area->m_zone->IsPersonalDungeon() == false) { tch = NULL; continue; } if (packet->multicount && !DEAD(ch)) { int multitarget = packet->list[packet->multicount].index; --packet->multicount; tch = area->FindCharInCell(ch, multitarget, (MSG_CHAR_TYPE)packet->tCharType); if (tch == NULL) { continue; } if (GetDistance(ch, tch) > ch->m_attackRange * 2) { tch = NULL; continue; } std::set<int>::iterator it = listMultiTarget.find(tch->m_index); if (it != listMultiTarget.end()) { GAMELOG << init("HACK ATTACK MULTI TARGET", pc) << "ZONE" << delim << pc->m_pZone->m_index << delim << "TARGET" << delim << packet->tCharType << delim << multitarget << end; if (pc->m_desc->IncreaseHackCount(1)) return ; tch = NULL; } } else { tch = NULL; continue; } if (packet->multicount <= 0) { tch = NULL; continue; } } // end while if (bAttackedPet && !ch->IsInPeaceZone(true)) pc->m_pulseLastAttackSkill = gserver->m_pulse; #ifdef EVENT_SEARCHFRIEND_TIME // 공격시 이벤트 시간 갱신 검사 if (gserver->m_bSearchFriendEvent && (pc->m_nEventSearchFriendListCount >= 1) && (pc->m_bEventSearchFriendSelect == true) && (pc->m_nTimeEventSearchFriend <= 216000) && bAttacked && !ch->IsInPeaceZone(true)) pc->m_pulseEventSearchFriend = gserver->m_pulse; #endif // #ifdef EVENT_SEARCHFRIEND_TIME }
// 믈리 어택 void do_pd_Attack(CPC* pc, CNetMsg::SP& msg) { CDratanCastle * pCastle = CDratanCastle::CreateInstance(); pCastle->CheckRespond(pc); RequestClient::doPDAttack* packet = reinterpret_cast<RequestClient::doPDAttack*>(msg->m_buf); if (packet->multicount > 20) { LOG_ERROR("HACKING : invalid multi count[%d]. charIndex[%d]", packet->multicount, pc->m_index); pc->m_desc->Close("invalid multi count"); return; } // multi target의 중복 검사 if (packet->multicount > 1) { std::set<int> tset; for (int i = 0; i < packet->multicount; ++i) { if (tset.insert(packet->list[i].index).second == false) { LOG_ERROR("HACKING : duplicate multi target[%d]. charIndex[%d]", packet->list[i].index, pc->m_index); pc->m_desc->Close("duplicate multi target"); return; } } } // 대상 검색 : 인접 셀에서만 CArea* area = pc->m_pArea; if (area == NULL) { LOG_ERROR("HACKING : not found area. charIndex[%d]", pc->m_index); pc->m_desc->Close("not found area"); return; } CCharacter* tch = area->FindCharInCell(pc, packet->tIndex, (MSG_CHAR_TYPE)packet->tCharType); if (tch == NULL) return; int preIndex = -1; for (int i = 0; i < packet->multicount; ++i) { if(preIndex == packet->list[i].index) { // 가까운 마을로 int nearZone; int nearZonePos; CZone* pZone = gserver->FindNearestZone(pc->m_pZone->m_index, GET_X(pc), GET_Z(pc), &nearZone, &nearZonePos); if (pZone == NULL) return; GoZone(pc, nearZone, pZone->m_zonePos[nearZonePos][0], // ylayer GetRandom(pZone->m_zonePos[nearZonePos][1], pZone->m_zonePos[nearZonePos][3]) / 2.0f, // x GetRandom(pZone->m_zonePos[nearZonePos][2], pZone->m_zonePos[nearZonePos][4]) / 2.0f); // z return; } preIndex = packet->list[i].index; CCharacter* ch = area->FindCharInCell(pc, packet->list[i].index, (MSG_CHAR_TYPE) MSG_CHAR_NPC); if(!ch) continue; if( !IS_NPC(ch) ) { CPC* bugPC = NULL; if( IS_ELEMENTAL(ch) ) { CElemental *ele = TO_ELEMENTAL(ch); bugPC = ele->GetOwner(); } if( IS_PET(ch) ) { CPet* pet = TO_PET(ch); bugPC = pet->GetOwner(); } if( IS_PC(ch) ) { bugPC = TO_PC(ch); } if( !bugPC ) return; // 가까운 마을로 int nearZone; int nearZonePos; CZone* pZone = gserver->FindNearestZone(bugPC->m_pZone->m_index, GET_X(bugPC), GET_Z(bugPC), &nearZone, &nearZonePos); if (pZone == NULL) return; GoZone(bugPC, nearZone, pZone->m_zonePos[nearZonePos][0], // ylayer GetRandom(pZone->m_zonePos[nearZonePos][1], pZone->m_zonePos[nearZonePos][3]) / 2.0f, // x GetRandom(pZone->m_zonePos[nearZonePos][2], pZone->m_zonePos[nearZonePos][4]) / 2.0f); // z GAMELOG << init("PD_BUG", bugPC) << end; return; } int ret = ProcAttack(ch, tch, ch->GetAttackType(NULL), NULL, 0); if (ret == -1) return ; } }