#include "stdafx.h" #include "constants.h" #include "pvp.h" #include "crc32.h" #include "packet.h" #include "desc.h" #include "desc_manager.h" #include "char.h" #include "char_manager.h" #include "config.h" #include "sectree_manager.h" #include "buffer_manager.h" #include "locale_service.h" using namespace std; CPVP::CPVP(DWORD dwPID1, DWORD dwPID2) { if (dwPID1 > dwPID2) { m_players[0].dwPID = dwPID1; m_players[1].dwPID = dwPID2; m_players[0].bAgree = true; } else { m_players[0].dwPID = dwPID2; m_players[1].dwPID = dwPID1; m_players[1].bAgree = true; } DWORD adwID[2]; adwID[0] = m_players[0].dwPID; adwID[1] = m_players[1].dwPID; m_dwCRC = GetFastHash((const char *) &adwID, 8); m_bRevenge = false; SetLastFightTime(); } CPVP::CPVP(CPVP & k) { m_players[0] = k.m_players[0]; m_players[1] = k.m_players[1]; m_dwCRC = k.m_dwCRC; m_bRevenge = k.m_bRevenge; SetLastFightTime(); } CPVP::~CPVP() { } void CPVP::Packet(bool bDelete) { if (!m_players[0].dwVID || !m_players[1].dwVID) { if (bDelete) sys_err("null vid when removing %u %u", m_players[0].dwVID, m_players[0].dwVID); return; } TPacketGCPVP pack; pack.bHeader = HEADER_GC_PVP; if (bDelete) { pack.bMode = PVP_MODE_NONE; pack.dwVIDSrc = m_players[0].dwVID; pack.dwVIDDst = m_players[1].dwVID; } else if (IsFight()) { pack.bMode = PVP_MODE_FIGHT; pack.dwVIDSrc = m_players[0].dwVID; pack.dwVIDDst = m_players[1].dwVID; } else { pack.bMode = m_bRevenge ? PVP_MODE_REVENGE : PVP_MODE_AGREE; if (m_players[0].bAgree) { pack.dwVIDSrc = m_players[0].dwVID; pack.dwVIDDst = m_players[1].dwVID; } else { pack.dwVIDSrc = m_players[1].dwVID; pack.dwVIDDst = m_players[0].dwVID; } } const DESC_MANAGER::DESC_SET & c_rSet = DESC_MANAGER::instance().GetClientSet(); DESC_MANAGER::DESC_SET::const_iterator it = c_rSet.begin(); while (it != c_rSet.end()) { LPDESC d = *it++; if (d->IsPhase(PHASE_GAME) || d->IsPhase(PHASE_DEAD)) d->Packet(&pack, sizeof(pack)); } } bool CPVP::Agree(DWORD dwPID) { m_players[m_players[0].dwPID != dwPID ? 1 : 0].bAgree = true; if (IsFight()) { Packet(); return true; } return false; } bool CPVP::IsFight() { return (m_players[0].bAgree == m_players[1].bAgree) && m_players[0].bAgree; } void CPVP::Win(DWORD dwPID) { int iSlot = m_players[0].dwPID != dwPID ? 1 : 0; m_bRevenge = true; m_players[iSlot].bAgree = true; // ÀÚµ¿À¸·Î µ¿ÀÇ m_players[!iSlot].bCanRevenge = true; m_players[!iSlot].bAgree = false; Packet(); } bool CPVP::CanRevenge(DWORD dwPID) { return m_players[m_players[0].dwPID != dwPID ? 1 : 0].bCanRevenge; } void CPVP::SetVID(DWORD dwPID, DWORD dwVID) { if (m_players[0].dwPID == dwPID) m_players[0].dwVID = dwVID; else m_players[1].dwVID = dwVID; } void CPVP::SetLastFightTime() { m_dwLastFightTime = get_dword_time(); } DWORD CPVP::GetLastFightTime() { return m_dwLastFightTime; } CPVPManager::CPVPManager() { } CPVPManager::~CPVPManager() { } void CPVPManager::Insert(LPCHARACTER pkChr, LPCHARACTER pkVictim) { if (pkChr->IsDead() || pkVictim->IsDead()) return; CPVP kPVP(pkChr->GetPlayerID(), pkVictim->GetPlayerID()); CPVP * pkPVP; if ((pkPVP = Find(kPVP.m_dwCRC))) { // º¹¼öÇÒ ¼ö ÀÖÀ¸¸é ¹Ù·Î ½Î¿ò! if (pkPVP->Agree(pkChr->GetPlayerID())) { pkVictim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s´Ô°úÀÇ ´ë°á ½ÃÀÛ!"), pkChr->GetName()); pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s´Ô°úÀÇ ´ë°á ½ÃÀÛ!"), pkVictim->GetName()); } return; } pkPVP = M2_NEW CPVP(kPVP); pkPVP->SetVID(pkChr->GetPlayerID(), pkChr->GetVID()); pkPVP->SetVID(pkVictim->GetPlayerID(), pkVictim->GetVID()); m_map_pkPVP.insert(map::value_type(pkPVP->m_dwCRC, pkPVP)); m_map_pkPVPSetByID[pkChr->GetPlayerID()].insert(pkPVP); m_map_pkPVPSetByID[pkVictim->GetPlayerID()].insert(pkPVP); pkPVP->Packet(); char msg[CHAT_MAX_LEN + 1]; snprintf(msg, sizeof(msg), LC_TEXT("%s´ÔÀÌ ´ë°á½ÅûÀ» Çß½À´Ï´Ù. ½Â³«ÇÏ·Á¸é ´ë°áµ¿ÀǸ¦ Çϼ¼¿ä."), pkChr->GetName()); pkVictim->ChatPacket(CHAT_TYPE_INFO, msg); pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s¿¡°Ô ´ë°á½ÅûÀ» Çß½À´Ï´Ù."), pkVictim->GetName()); // NOTIFY_PVP_MESSAGE LPDESC pkVictimDesc = pkVictim->GetDesc(); if (pkVictimDesc) { TPacketGCWhisper pack; int len = MIN(CHAT_MAX_LEN, strlen(msg) + 1); pack.bHeader = HEADER_GC_WHISPER; pack.wSize = sizeof(TPacketGCWhisper) + len; pack.bType = WHISPER_TYPE_SYSTEM; strlcpy(pack.szNameFrom, pkChr->GetName(), sizeof(pack.szNameFrom)); TEMP_BUFFER buf; buf.write(&pack, sizeof(TPacketGCWhisper)); buf.write(msg, len); pkVictimDesc->Packet(buf.read_peek(), buf.size()); } // END_OF_NOTIFY_PVP_MESSAGE } void CPVPManager::ConnectEx(LPCHARACTER pkChr, bool bDisconnect) { CPVPSetMap::iterator it = m_map_pkPVPSetByID.find(pkChr->GetPlayerID()); if (it == m_map_pkPVPSetByID.end()) return; DWORD dwVID = bDisconnect ? 0 : pkChr->GetVID(); TR1_NS::unordered_set::iterator it2 = it->second.begin(); while (it2 != it->second.end()) { CPVP * pkPVP = *it2++; pkPVP->SetVID(pkChr->GetPlayerID(), dwVID); } } void CPVPManager::Connect(LPCHARACTER pkChr) { ConnectEx(pkChr, false); } void CPVPManager::Disconnect(LPCHARACTER pkChr) { //ConnectEx(pkChr, true); } void CPVPManager::GiveUp(LPCHARACTER pkChr, DWORD dwKillerPID) // This method is calling from no where yet. { CPVPSetMap::iterator it = m_map_pkPVPSetByID.find(pkChr->GetPlayerID()); if (it == m_map_pkPVPSetByID.end()) return; sys_log(1, "PVPManager::Dead %d", pkChr->GetPlayerID()); TR1_NS::unordered_set::iterator it2 = it->second.begin(); while (it2 != it->second.end()) { CPVP * pkPVP = *it2++; DWORD dwCompanionPID; if (pkPVP->m_players[0].dwPID == pkChr->GetPlayerID()) dwCompanionPID = pkPVP->m_players[1].dwPID; else dwCompanionPID = pkPVP->m_players[0].dwPID; if (dwCompanionPID != dwKillerPID) continue; pkPVP->SetVID(pkChr->GetPlayerID(), 0); m_map_pkPVPSetByID.erase(dwCompanionPID); it->second.erase(pkPVP); if (it->second.empty()) m_map_pkPVPSetByID.erase(it); m_map_pkPVP.erase(pkPVP->m_dwCRC); pkPVP->Packet(true); M2_DELETE(pkPVP); break; } } // ¸®ÅÏ°ª: 0 = PK, 1 = PVP // PVP¸¦ ¸®ÅÏÇÏ¸é °æÇèÄ¡³ª ¾ÆÀÌÅÛÀ» ¶³±¸°í PK¸é ¶³±¸Áö ¾Ê´Â´Ù. bool CPVPManager::Dead(LPCHARACTER pkChr, DWORD dwKillerPID) { CPVPSetMap::iterator it = m_map_pkPVPSetByID.find(pkChr->GetPlayerID()); if (it == m_map_pkPVPSetByID.end()) return false; bool found = false; sys_log(1, "PVPManager::Dead %d", pkChr->GetPlayerID()); TR1_NS::unordered_set::iterator it2 = it->second.begin(); while (it2 != it->second.end()) { CPVP * pkPVP = *it2++; DWORD dwCompanionPID; if (pkPVP->m_players[0].dwPID == pkChr->GetPlayerID()) dwCompanionPID = pkPVP->m_players[1].dwPID; else dwCompanionPID = pkPVP->m_players[0].dwPID; if (dwCompanionPID == dwKillerPID) { if (pkPVP->IsFight()) { pkPVP->SetLastFightTime(); pkPVP->Win(dwKillerPID); found = true; break; } else if (get_dword_time() - pkPVP->GetLastFightTime() <= 15000) { found = true; break; } } } return found; } bool CPVPManager::CanAttack(LPCHARACTER pkChr, LPCHARACTER pkVictim) { switch (pkVictim->GetCharType()) { case CHAR_TYPE_NPC: case CHAR_TYPE_WARP: case CHAR_TYPE_GOTO: return false; } if (pkChr == pkVictim) // ³»°¡ ³¯ Ä¥¶ó°í ÇÏ³× -_- return false; if (pkVictim->IsNPC() && pkChr->IsNPC() && !pkChr->IsGuardNPC()) return false; if( true == pkChr->IsHorseRiding() ) { if( pkChr->GetHorseLevel() > 0 && 1 == pkChr->GetHorseGrade() ) return false; } else { switch( pkChr->GetMountVnum() ) { case 0: case 20030: case 20110: case 20111: case 20112: case 20113: case 20114: case 20115: case 20116: case 20117: case 20118: //½Å±Ô Å»°Í °í±Þ case 20205: case 20206: case 20207: case 20208: case 20209: case 20210: case 20211: case 20212: case 20119: // ¶ó¸¶´Ü È渶 case 20219: // ¶ó¸¶´Ü È渶 Ŭ·Ð (ÇÒ·ÎÀ©¿ë) case 20220: // Å©¸®½º¸¶½º Å»°Í case 20221: // Àü°© ¹é¿õ case 20222: // Àü°© ÆÒ´õ case 20120: case 20121: case 20122: case 20123: case 20124: case 20125: case 20214: // ³­ÆøÇÑ Àü°©¼ø¼ø·Ï case 20215: // ¿ë¸ÍÇÑ Àü°©¼ø¼ø·Ï case 20217: // ³­ÆøÇÑ Àü°©¾Ï¼ø·Ï case 20218: // ¿ë¸ÍÇÑ Àü°©¾Ï¼ø·Ï break; default: return false; } } if (pkVictim->IsNPC() || pkChr->IsNPC()) { return true; } if (pkVictim->IsObserverMode() || pkChr->IsObserverMode()) return false; { BYTE bMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(pkChr->GetMapIndex()); if ( pkChr->GetPKMode() == PK_MODE_PROTECT && pkChr->GetEmpire() == bMapEmpire || pkVictim->GetPKMode() == PK_MODE_PROTECT && pkVictim->GetEmpire() == bMapEmpire ) { return false; } } if (pkChr->GetEmpire() != pkVictim->GetEmpire()) { if ( LC_IsYMIR() == true || LC_IsKorea() == true ) { if ( pkChr->GetPKMode() == PK_MODE_PROTECT || pkVictim->GetPKMode() == PK_MODE_PROTECT ) { return false; } } return true; } bool beKillerMode = false; if (pkVictim->GetParty() && pkVictim->GetParty() == pkChr->GetParty()) { return false; // Cannot attack same party on any pvp model } else { if (pkVictim->IsKillerMode()) { return true; } if (pkChr->GetAlignment() < 0 && pkVictim->GetAlignment() >= 0) { if (g_protectNormalPlayer) { // ¹ü¹ýÀÚ´Â ÆòÈ­¸ðµåÀÎ ÂøÇÑ»ç¶÷À» °ø°ÝÇÒ ¼ö ¾ø´Ù. if (PK_MODE_PEACE == pkVictim->GetPKMode()) return false; } } switch (pkChr->GetPKMode()) { case PK_MODE_PEACE: case PK_MODE_REVENGE: // Cannot attack same guild if (pkVictim->GetGuild() && pkVictim->GetGuild() == pkChr->GetGuild()) break; if (pkChr->GetPKMode() == PK_MODE_REVENGE) { //if (!g_iUseLocale) if (1) { if (pkChr->GetAlignment() < 0 && pkVictim->GetAlignment() >= 0) { pkChr->SetKillerMode(true); return true; } else if (pkChr->GetAlignment() >= 0 && pkVictim->GetAlignment() < 0) return true; } else { if (pkChr->GetAlignment() < 0 && pkVictim->GetAlignment() < 0) break; else if (pkChr->GetAlignment() >= 0 && pkVictim->GetAlignment() >= 0) break; beKillerMode = true; } } break; case PK_MODE_GUILD: // Same implementation from PK_MODE_FREE except for attacking same guild if (!pkChr->GetGuild() || (pkVictim->GetGuild() != pkChr->GetGuild())) { if (1) //if (!g_iUseLocale) { if (pkVictim->GetAlignment() >= 0) pkChr->SetKillerMode(true); else if (pkChr->GetAlignment() < 0 && pkVictim->GetAlignment() < 0) pkChr->SetKillerMode(true); return true; } else beKillerMode = true; } break; case PK_MODE_FREE: //if (!g_iUseLocale) if (1) { if (pkVictim->GetAlignment() >= 0) pkChr->SetKillerMode(true); else if (pkChr->GetAlignment() < 0 && pkVictim->GetAlignment() < 0) pkChr->SetKillerMode(true); return true; } else beKillerMode = true; break; } } CPVP kPVP(pkChr->GetPlayerID(), pkVictim->GetPlayerID()); CPVP * pkPVP = Find(kPVP.m_dwCRC); if (!pkPVP || !pkPVP->IsFight()) { if (beKillerMode) pkChr->SetKillerMode(true); return (beKillerMode); } pkPVP->SetLastFightTime(); return true; } CPVP * CPVPManager::Find(DWORD dwCRC) { map::iterator it = m_map_pkPVP.find(dwCRC); if (it == m_map_pkPVP.end()) return NULL; return it->second; } void CPVPManager::Delete(CPVP * pkPVP) { map::iterator it = m_map_pkPVP.find(pkPVP->m_dwCRC); if (it == m_map_pkPVP.end()) return; m_map_pkPVP.erase(it); m_map_pkPVPSetByID[pkPVP->m_players[0].dwPID].erase(pkPVP); m_map_pkPVPSetByID[pkPVP->m_players[1].dwPID].erase(pkPVP); M2_DELETE(pkPVP); } void CPVPManager::SendList(LPDESC d) { map::iterator it = m_map_pkPVP.begin(); DWORD dwVID = d->GetCharacter()->GetVID(); TPacketGCPVP pack; pack.bHeader = HEADER_GC_PVP; while (it != m_map_pkPVP.end()) { CPVP * pkPVP = (it++)->second; if (!pkPVP->m_players[0].dwVID || !pkPVP->m_players[1].dwVID) continue; // VID°¡ µÑ´Ù ÀÖÀ» °æ¿ì¿¡¸¸ º¸³½´Ù. if (pkPVP->IsFight()) { pack.bMode = PVP_MODE_FIGHT; pack.dwVIDSrc = pkPVP->m_players[0].dwVID; pack.dwVIDDst = pkPVP->m_players[1].dwVID; } else { pack.bMode = pkPVP->m_bRevenge ? PVP_MODE_REVENGE : PVP_MODE_AGREE; if (pkPVP->m_players[0].bAgree) { pack.dwVIDSrc = pkPVP->m_players[0].dwVID; pack.dwVIDDst = pkPVP->m_players[1].dwVID; } else { pack.dwVIDSrc = pkPVP->m_players[1].dwVID; pack.dwVIDDst = pkPVP->m_players[0].dwVID; } } d->Packet(&pack, sizeof(pack)); sys_log(1, "PVPManager::SendList %d %d", pack.dwVIDSrc, pack.dwVIDDst); if (pkPVP->m_players[0].dwVID == dwVID) { LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(pkPVP->m_players[1].dwVID); if (ch && ch->GetDesc()) { LPDESC d = ch->GetDesc(); d->Packet(&pack, sizeof(pack)); } } else if (pkPVP->m_players[1].dwVID == dwVID) { LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(pkPVP->m_players[0].dwVID); if (ch && ch->GetDesc()) { LPDESC d = ch->GetDesc(); d->Packet(&pack, sizeof(pack)); } } } } void CPVPManager::Process() { map::iterator it = m_map_pkPVP.begin(); while (it != m_map_pkPVP.end()) { CPVP * pvp = (it++)->second; if (get_dword_time() - pvp->GetLastFightTime() > 600000) // 10ºÐ ÀÌ»ó ½Î¿òÀÌ ¾ø¾úÀ¸¸é { pvp->Packet(true); Delete(pvp); } } }