DarkflameServer/dGame/dComponents/RocketLaunchpadControlComponent.cpp
2021-12-05 18:54:36 +01:00

215 lines
5.7 KiB
C++

#include "RocketLaunchpadControlComponent.h"
#include <sstream>
#include "GameMessages.h"
#include "CharacterComponent.h"
#include "dZoneManager.h"
#include "EntityManager.h"
#include "Item.h"
#include "Game.h"
#include "dLogger.h"
#include "CDClientDatabase.h"
#include "ChatPackets.h"
#include "MissionComponent.h"
#include "PropertyEntranceComponent.h"
#include "dServer.h"
#include "dMessageIdentifiers.h"
#include "PacketUtils.h"
RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, int rocketId) : Component(parent) {
std::stringstream query;
query << "SELECT targetZone, defaultZoneID, targetScene, altLandingPrecondition, altLandingSpawnPointName FROM RocketLaunchpadControlComponent WHERE id = " << std::to_string(rocketId);
auto result = CDClientDatabase::ExecuteQuery(query.str());
if (!result.eof() && !result.fieldIsNull(0))
{
m_TargetZone = result.getIntField(0);
m_DefaultZone = result.getIntField(1);
m_TargetScene = result.getStringField(2);
m_AltPrecondition = new PreconditionExpression(result.getStringField(3));
m_AltLandingScene = result.getStringField(4);
}
result.finalize();
}
RocketLaunchpadControlComponent::~RocketLaunchpadControlComponent() {
delete m_AltPrecondition;
}
void RocketLaunchpadControlComponent::RocketEquip(Entity* entity, LWOOBJID rocketID) {
if (m_PlayersInRadius.find(entity->GetObjectID()) != m_PlayersInRadius.end()) {
Launch(entity, rocketID);
//Go ahead and save the player
//This causes a double-save, but it should prevent players from not being saved
//before the next world server starts loading their data.
if (entity->GetCharacter())
entity->GetCharacter()->SaveXMLToDatabase();
}
}
void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOOBJID optionalRocketID, LWOMAPID mapId, LWOCLONEID cloneId) {
auto zone = mapId == LWOMAPID_INVALID ? m_TargetZone : mapId;
if (zone == 0)
{
return;
}
TellMasterToPrepZone(zone);
// This also gets triggered by a proximity monitor + item equip, I will set that up when havok is ready
auto* inventoryComponent = originator->GetComponent<InventoryComponent>();
auto* characterComponent = originator->GetComponent<CharacterComponent>();
auto* character = originator->GetCharacter();
if (inventoryComponent == nullptr || characterComponent == nullptr || character == nullptr) {
return;
}
// Select the rocket
Item* rocket = nullptr;
if (optionalRocketID != LWOOBJID_EMPTY)
{
rocket = inventoryComponent->FindItemById(optionalRocketID);
}
if (rocket == nullptr)
{
rocket = inventoryComponent->FindItemById(characterComponent->GetLastRocketItemID());
}
if (rocket == nullptr)
{
rocket = inventoryComponent->FindItemByLot(6416);
}
if (rocket == nullptr)
{
Game::logger->Log("RocketLaunchpadControlComponent", "Unable to find rocket (%llu)!\n", optionalRocketID);
return;
}
if (rocket->GetConfig().empty()) // Sanity check
{
rocket->SetCount(0, false, false);
return;
}
// Achievement unlocked: "All zones unlocked"
if (!m_AltLandingScene.empty() && m_AltPrecondition->Check(originator)) {
character->SetTargetScene(m_AltLandingScene);
}
else {
character->SetTargetScene(m_TargetScene);
}
if (characterComponent) {
for (LDFBaseData* data : rocket->GetConfig()) {
if (data->GetKey() == u"assemblyPartLOTs") {
std::string newRocketStr;
for (char character : data->GetValueAsString()) {
if (character == '+') {
newRocketStr.push_back(';');
}
else {
newRocketStr.push_back(character);
}
}
newRocketStr.push_back(';');
characterComponent->SetLastRocketConfig(GeneralUtils::ASCIIToUTF16(newRocketStr));
}
}
}
// Store the last used rocket item's ID
characterComponent->SetLastRocketItemID(rocket->GetId());
characterComponent->UpdatePlayerStatistic(RocketsUsed);
character->SaveXMLToDatabase();
SetSelectedMapId(originator->GetObjectID(), zone);
GameMessages::SendFireEventClientSide(m_Parent->GetObjectID(), originator->GetSystemAddress(), u"RocketEquipped", rocket->GetId(), cloneId, -1, originator->GetObjectID());
rocket->Equip(true);
GameMessages::SendChangeObjectWorldState(rocket->GetId(), WORLDSTATE_ATTACHED, UNASSIGNED_SYSTEM_ADDRESS);
EntityManager::Instance()->SerializeEntity(originator);
}
void RocketLaunchpadControlComponent::OnUse(Entity* originator) {
auto* propertyEntrance = m_Parent->GetComponent<PropertyEntranceComponent>();
if (propertyEntrance != nullptr)
{
propertyEntrance->OnUse(originator);
return;
}
Launch(originator);
}
void RocketLaunchpadControlComponent::OnProximityUpdate(Entity* entering, std::string name, std::string status) {
// Proximity rockets are handled by item equipment
}
void RocketLaunchpadControlComponent::SetSelectedMapId(LWOOBJID player, LWOMAPID mapID)
{
m_SelectedMapIds[player] = mapID;
}
LWOMAPID RocketLaunchpadControlComponent::GetSelectedMapId(LWOOBJID player) const
{
const auto index = m_SelectedMapIds.find(player);
if (index == m_SelectedMapIds.end()) return 0;
return index->second;
}
void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId)
{
m_SelectedCloneIds[player] = cloneId;
}
LWOCLONEID RocketLaunchpadControlComponent::GetSelectedCloneId(LWOOBJID player) const
{
const auto index = m_SelectedCloneIds.find(player);
if (index == m_SelectedCloneIds.end()) return 0;
return index->second;
}
void RocketLaunchpadControlComponent::TellMasterToPrepZone(int zoneID) {
CBITSTREAM;
PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_PREP_ZONE);
bitStream.Write(zoneID);
Game::server->SendToMaster(&bitStream);
}
LWOMAPID RocketLaunchpadControlComponent::GetTargetZone() const
{
return m_TargetZone;
}
LWOMAPID RocketLaunchpadControlComponent::GetDefaultZone() const
{
return m_DefaultZone;
}