#include "ProjectileAttackBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" #include "Game.h" #include "dLogger.h" #include "SkillComponent.h" #include "../dWorldServer/ObjectIDManager.h" #include "eObjectBits.h" void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { LWOOBJID target{}; if (!bitStream->Read(target)) { Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); return; }; auto* entity = EntityManager::Instance()->GetEntity(context->originator); if (entity == nullptr) { Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator); return; } auto skillComponent = entity->GetComponent(); if (skillComponent == nullptr) { Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", -context->originator); return; } if (m_useMouseposit && !branch.isSync) { NiPoint3 targetPosition = NiPoint3::ZERO; if (!bitStream->Read(targetPosition)) { Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); return; }; } auto* targetEntity = EntityManager::Instance()->GetEntity(target); for (auto i = 0u; i < this->m_projectileCount; ++i) { LWOOBJID projectileId{}; if (!bitStream->Read(projectileId)) { Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); return; }; branch.target = target; branch.isProjectile = true; branch.referencePosition = targetEntity == nullptr ? entity->GetPosition() : targetEntity->GetPosition(); skillComponent->RegisterPlayerProjectile(projectileId, context, branch, this->m_lot); } } void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { bitStream->Write(branch.target); auto* entity = EntityManager::Instance()->GetEntity(context->originator); if (entity == nullptr) { Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator); return; } auto skillComponent = entity->GetComponent(); if (skillComponent == nullptr) { Game::logger->Log("ProjectileAttackBehavior", "Failed to find skill component for (%llu)!", context->originator); return; } auto* other = EntityManager::Instance()->GetEntity(branch.target); if (other == nullptr) { Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target); return; } const auto position = entity->GetPosition() + this->m_offset; const auto distance = Vector3::Distance(position, other->GetPosition()); const auto time = distance / this->m_projectileSpeed; const auto rotation = NiQuaternion::LookAtUnlocked(position, other->GetPosition()); const auto targetPosition = other->GetPosition(); //entity->SetRotation(rotation); const auto angleDelta = this->m_spreadAngle; const auto angleStep = angleDelta / this->m_projectileCount; auto angle = -angleStep; const auto maxTime = this->m_maxDistance / this->m_projectileSpeed; for (auto i = 0u; i < this->m_projectileCount; ++i) { auto id = static_cast(ObjectIDManager::Instance()->GenerateObjectID()); GeneralUtils::SetBit(id, eObjectBits::SPAWNED); bitStream->Write(id); auto eulerAngles = rotation.GetEulerAngles(); eulerAngles.y += angle * (3.14 / 180); const auto angledRotation = NiQuaternion::FromEulerAngles(eulerAngles); const auto direction = angledRotation.GetForwardVector(); const auto destination = position + direction * distance; branch.isProjectile = true; branch.referencePosition = destination; skillComponent->RegisterCalculatedProjectile(id, context, branch, this->m_lot, maxTime, position, direction * this->m_projectileSpeed, this->m_trackTarget, this->m_trackRadius); // No idea how to calculate this properly if (this->m_projectileCount == 2) { angle += angleDelta; } else if (this->m_projectileCount == 3) { angle += angleStep; } } } void ProjectileAttackBehavior::Load() { this->m_lot = GetInt("LOT_ID"); this->m_projectileCount = GetInt("spread_count"); if (this->m_projectileCount == 0) { this->m_projectileCount = 1; } this->m_maxDistance = GetFloat("max_distance"); this->m_projectileSpeed = GetFloat("projectile_speed"); this->m_spreadAngle = GetFloat("spread_angle"); this->m_offset = { GetFloat("offset_x"), GetFloat("offset_y"), GetFloat("offset_z") }; this->m_trackTarget = GetBoolean("track_target"); this->m_trackRadius = GetFloat("track_radius"); this->m_useMouseposit = GetBoolean("use_mouseposit"); this->m_ProjectileType = GetInt("projectile_type"); }