#include "stdafx.h" #include "config.h" #include "utils.h" #include "vector.h" #include "char.h" #include "sectree_manager.h" #include "char_manager.h" #include "mob_manager.h" #include "PetSystem.h" #include "../../common/VnumHelper.h" #include "packet.h" #include "item_manager.h" #include "item.h" EVENTINFO(petsystem_event_info) { CPetSystem* pPetSystem; }; EVENTFUNC(petsystem_update_event) { petsystem_event_info* info = dynamic_cast( event->info ); if ( info == NULL ) { sys_err( "check_speedhack_event> Null pointer" ); return 0; } CPetSystem* pPetSystem = info->pPetSystem; if (NULL == pPetSystem) return 0; pPetSystem->Update(0); return PASSES_PER_SEC(1) / 4; } /////////////////////////////////////////////////////////////////////////////////////// // CPetActor /////////////////////////////////////////////////////////////////////////////////////// CPetActor::CPetActor(LPCHARACTER owner, DWORD vnum, DWORD options) { m_dwVnum = vnum; m_dwVID = 0; m_dwOptions = options; m_dwLastActionTime = 0; m_pkChar = 0; m_pkOwner = owner; m_originalMoveSpeed = 0; m_dwSummonItemVID = 0; m_dwSummonItemVnum = 0; } CPetActor::~CPetActor() { this->Unsummon( #ifdef USE_ACTIVE_PET_SEAL_EFFECT false #endif ); m_pkOwner = 0; } void CPetActor::SetName(const char* name) { std::string petName = m_pkOwner->GetName(); petName += "'s "; petName += (name) ? name : "Pet"; if (IsSummoned()) m_pkChar->SetName(petName); m_name = petName; } bool CPetActor::Mount() { if (0 == m_pkOwner) return false; if (true == HasOption(EPetOption_Mountable)) m_pkOwner->MountVnum(m_dwVnum); return m_pkOwner->GetMountVnum() == m_dwVnum;; } void CPetActor::Unmount() { if (0 == m_pkOwner) return; if (m_pkOwner->IsHorseRiding()) m_pkOwner->StopRiding(); } void CPetActor::Unsummon( #ifdef USE_ACTIVE_PET_SEAL_EFFECT bool updateSocket #endif ) { if (true == this->IsSummoned()) { this->ClearBuff(); this->SetSummonItem(NULL #ifdef USE_ACTIVE_PET_SEAL_EFFECT , updateSocket #endif ); if (NULL != m_pkOwner) m_pkOwner->ComputePoints(); if (NULL != m_pkChar) M2_DESTROY_CHARACTER(m_pkChar); m_pkChar = 0; m_dwVID = 0; } } DWORD CPetActor::Summon(const char* petName, LPITEM pSummonItem, bool bSpawnFar) { long x = m_pkOwner->GetX(); long y = m_pkOwner->GetY(); long z = m_pkOwner->GetZ(); if (true == bSpawnFar) { x += (number(0, 1) * 2 - 1) * number(2000, 2500); y += (number(0, 1) * 2 - 1) * number(2000, 2500); } else { x += number(-100, 100); y += number(-100, 100); } if (0 != m_pkChar) { m_pkChar->Show (m_pkOwner->GetMapIndex(), x, y); m_dwVID = m_pkChar->GetVID(); return m_dwVID; } m_pkChar = CHARACTER_MANAGER::instance().SpawnMob( m_dwVnum, m_pkOwner->GetMapIndex(), x, y, z, false, (int)(m_pkOwner->GetRotation()+180), false); if (0 == m_pkChar) { sys_err("[CPetSystem::Summon] Failed to summon the pet. (vnum: %d)", m_dwVnum); return 0; } m_pkChar->SetPet(); m_pkChar->SetEmpire(m_pkOwner->GetEmpire()); m_dwVID = m_pkChar->GetVID(); this->SetName(petName); this->SetSummonItem(pSummonItem); m_pkOwner->ComputePoints(); m_pkChar->Show(m_pkOwner->GetMapIndex(), x, y, z); return m_dwVID; } bool CPetActor::_UpdatAloneActionAI(float fMinDist, float fMaxDist) { float fDist = number(fMinDist, fMaxDist); float r = (float)number (0, 359); float dest_x = GetOwner()->GetX() + fDist * cos(r); float dest_y = GetOwner()->GetY() + fDist * sin(r); m_pkChar->SetNowWalking(true); if (!m_pkChar->IsStateMove() && m_pkChar->Goto(dest_x, dest_y)) m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0); m_dwLastActionTime = get_dword_time(); return true; } bool CPetActor::_UpdateFollowAI() { if (0 == m_pkChar->m_pkMobData) { //sys_err("[CPetActor::_UpdateFollowAI] m_pkChar->m_pkMobData is NULL"); return false; } if (0 == m_originalMoveSpeed) { const CMob* mobData = CMobManager::Instance().Get(m_dwVnum); if (0 != mobData) m_originalMoveSpeed = mobData->m_table.sMovingSpeed; } float START_FOLLOW_DISTANCE = 300.0f; float START_RUN_DISTANCE = 900.0f; float RESPAWN_DISTANCE = 4500.f; int APPROACH = 200; bool bRun = false; DWORD currentTime = get_dword_time(); long ownerX = m_pkOwner->GetX(); long ownerY = m_pkOwner->GetY(); long charX = m_pkChar->GetX(); long charY = m_pkChar->GetY(); float fDist = DISTANCE_APPROX(charX - ownerX, charY - ownerY); if (fDist >= RESPAWN_DISTANCE) { float fOwnerRot = m_pkOwner->GetRotation() * 3.141592f / 180.f; float fx = -APPROACH * cos(fOwnerRot); float fy = -APPROACH * sin(fOwnerRot); if (m_pkChar->Show(m_pkOwner->GetMapIndex(), ownerX + fx, ownerY + fy)) { return true; } } if (fDist >= START_FOLLOW_DISTANCE) { if( fDist >= START_RUN_DISTANCE) { bRun = true; } m_pkChar->SetNowWalking(!bRun); Follow(APPROACH); m_pkChar->SetLastAttacked(currentTime); m_dwLastActionTime = currentTime; } else m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0); return true; } bool CPetActor::Update(DWORD deltaTime) { bool bResult = true; if (m_pkOwner->IsDead() || (IsSummoned() && m_pkChar->IsDead()) || NULL == ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID()) || ITEM_MANAGER::instance().FindByVID(this->GetSummonItemVID())->GetOwner() != this->GetOwner() ) { this->Unsummon(); return true; } if (this->IsSummoned() && HasOption(EPetOption_Followable)) bResult = bResult && this->_UpdateFollowAI(); return bResult; } bool CPetActor::Follow(float fMinDistance) { if( !m_pkOwner || !m_pkChar) return false; float fOwnerX = m_pkOwner->GetX(); float fOwnerY = m_pkOwner->GetY(); float fPetX = m_pkChar->GetX(); float fPetY = m_pkChar->GetY(); float fDist = DISTANCE_SQRT(fOwnerX - fPetX, fOwnerY - fPetY); if (fDist <= fMinDistance) return false; m_pkChar->SetRotationToXY(fOwnerX, fOwnerY); float fx, fy; float fDistToGo = fDist - fMinDistance; GetDeltaByDegree(m_pkChar->GetRotation(), fDistToGo, &fx, &fy); if (!m_pkChar->Goto((int)(fPetX+fx+0.5f), (int)(fPetY+fy+0.5f)) ) return false; m_pkChar->SendMovePacket(FUNC_WAIT, 0, 0, 0, 0, 0); return true; } bool CPetActor::SetSummonItem(LPITEM pItem #ifdef USE_ACTIVE_PET_SEAL_EFFECT , bool updateSocket #endif ) { if (!pItem) { #ifdef USE_ACTIVE_PET_SEAL_EFFECT LPITEM pSummonItem = ITEM_MANAGER::instance().FindByVID(m_dwSummonItemVID); if (pSummonItem && updateSocket) pSummonItem->SetSocket(PET_SEAL_ACTIVE_SOCKET_IDX, false); #endif m_dwSummonItemVID = 0; m_dwSummonItemVnum = 0; return false; } #ifdef USE_ACTIVE_PET_SEAL_EFFECT pItem->SetSocket(PET_SEAL_ACTIVE_SOCKET_IDX, true); #endif m_dwSummonItemVID = pItem->GetVID(); m_dwSummonItemVnum = pItem->GetVnum(); return true; } bool __PetCheckBuff(const CPetActor* pPetActor) { bool bMustHaveBuff = true; switch (pPetActor->GetVnum()) { case 34004: case 34009: if (!pPetActor->GetOwner()->GetDungeon()) bMustHaveBuff = false; default: break; } return bMustHaveBuff; } void CPetActor::GiveBuff() { if (!__PetCheckBuff(this)) return; LPITEM item = ITEM_MANAGER::instance().FindByVID(m_dwSummonItemVID); if (item) item->ModifyPoints(true); return ; } void CPetActor::ClearBuff() { if (NULL == m_pkOwner) return ; TItemTable* item_proto = ITEM_MANAGER::instance().GetTable(m_dwSummonItemVnum); if (NULL == item_proto) return; if (!__PetCheckBuff(this)) // @fixme129 return; for (int i = 0; i < ITEM_APPLY_MAX_NUM; i++) { if (item_proto->aApplies[i].bType == APPLY_NONE) continue; m_pkOwner->ApplyPoint(item_proto->aApplies[i].bType, -item_proto->aApplies[i].lValue); } return ; } /////////////////////////////////////////////////////////////////////////////////////// // CPetSystem /////////////////////////////////////////////////////////////////////////////////////// CPetSystem::CPetSystem(LPCHARACTER owner) { // assert(0 != owner && "[CPetSystem::CPetSystem] Invalid owner"); m_pkOwner = owner; m_dwUpdatePeriod = 400; m_dwLastUpdateTime = 0; } CPetSystem::~CPetSystem() { Destroy(); } void CPetSystem::Destroy() { for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) { CPetActor* petActor = iter->second; if (0 != petActor) { delete petActor; } } event_cancel(&m_pkPetSystemUpdateEvent); m_petActorMap.clear(); } bool CPetSystem::Update(DWORD deltaTime) { bool bResult = true; DWORD currentTime = get_dword_time(); if (m_dwUpdatePeriod > currentTime - m_dwLastUpdateTime) return true; std::vector v_garbageActor; for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) { CPetActor* petActor = iter->second; if (0 != petActor && petActor->IsSummoned()) { LPCHARACTER pPet = petActor->GetCharacter(); if (NULL == CHARACTER_MANAGER::instance().Find(pPet->GetVID())) { v_garbageActor.emplace_back(petActor); } else { bResult = bResult && petActor->Update(deltaTime); } } } for (std::vector::iterator it = v_garbageActor.begin(); it != v_garbageActor.end(); it++) DeletePet(*it); m_dwLastUpdateTime = currentTime; return bResult; } void CPetSystem::DeletePet(DWORD mobVnum) { TPetActorMap::iterator iter = m_petActorMap.find(mobVnum); if (m_petActorMap.end() == iter) { sys_err("[CPetSystem::DeletePet] Can't find pet on my list (VNUM: %d)", mobVnum); return; } CPetActor* petActor = iter->second; if (0 == petActor) sys_err("[CPetSystem::DeletePet] Null Pointer (petActor)"); else delete petActor; m_petActorMap.erase(iter); } void CPetSystem::DeletePet(CPetActor* petActor) { for (TPetActorMap::iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) { if (iter->second == petActor) { delete petActor; m_petActorMap.erase(iter); return; } } sys_err("[CPetSystem::DeletePet] Can't find petActor(0x%x) on my list(size: %d) ", petActor, m_petActorMap.size()); } void CPetSystem::Unsummon(DWORD vnum, bool bDeleteFromList) { CPetActor* actor = this->GetByVnum(vnum); if (0 == actor) { sys_err("[CPetSystem::GetByVnum(%d)] Null Pointer (petActor)", vnum); return; } actor->Unsummon(); if (true == bDeleteFromList) this->DeletePet(actor); bool bActive = false; for (TPetActorMap::iterator it = m_petActorMap.begin(); it != m_petActorMap.end(); it++) { bActive |= it->second->IsSummoned(); } if (false == bActive) { event_cancel(&m_pkPetSystemUpdateEvent); m_pkPetSystemUpdateEvent = NULL; } } void CPetSystem::UnsummonAll() { for (auto & iter : m_petActorMap) { auto * actor = iter.second; if (actor) actor->Unsummon(); } bool bActive = false; for (auto & it : m_petActorMap) bActive |= it.second->IsSummoned(); if (!bActive) { event_cancel(&m_pkPetSystemUpdateEvent); m_pkPetSystemUpdateEvent = nullptr; } } CPetActor* CPetSystem::Summon(DWORD mobVnum, LPITEM pSummonItem, const char* petName, bool bSpawnFar, DWORD options) { CPetActor* petActor = this->GetByVnum(mobVnum); if (0 == petActor) { petActor = M2_NEW CPetActor(m_pkOwner, mobVnum, options); m_petActorMap.emplace(mobVnum, petActor); } #ifdef ENABLE_NEWSTUFF DWORD petVID = petActor->Summon(petName, pSummonItem, bSpawnFar); if (!petVID) sys_err("[CPetSystem::Summon(%d)] Null Pointer (petVID)", pSummonItem); #endif if (NULL == m_pkPetSystemUpdateEvent) { petsystem_event_info* info = AllocEventInfo(); info->pPetSystem = this; m_pkPetSystemUpdateEvent = event_create(petsystem_update_event, info, PASSES_PER_SEC(1) / 4); } return petActor; } CPetActor* CPetSystem::GetByVID(DWORD vid) const { CPetActor* petActor = 0; bool bFound = false; for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) { petActor = iter->second; if (0 == petActor) { sys_err("[CPetSystem::GetByVID(%d)] Null Pointer (petActor)", vid); continue; } bFound = petActor->GetVID() == vid; if (true == bFound) break; } return bFound ? petActor : 0; } CPetActor* CPetSystem::GetByVnum(DWORD vnum) const { CPetActor* petActor = 0; TPetActorMap::const_iterator iter = m_petActorMap.find(vnum); if (m_petActorMap.end() != iter) petActor = iter->second; return petActor; } size_t CPetSystem::CountSummoned() const { size_t count = 0; for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) { CPetActor* petActor = iter->second; if (0 != petActor) { if (petActor->IsSummoned()) ++count; } } return count; } void CPetSystem::RefreshBuff() { for (TPetActorMap::const_iterator iter = m_petActorMap.begin(); iter != m_petActorMap.end(); ++iter) { CPetActor* petActor = iter->second; if (petActor && petActor->IsSummoned()) petActor->GiveBuff(); } } //martysama0134's 623a0779c74cb7565145d45548376308