DarkflameServer/dScripts/02_server/Map/General/PetDigServer.cpp
David Markowitz 455f9470a5
Move EntityManager to Game namespace (#1140)
* Move EntityManager to Game namespace

* move initialization to later

Need to wait for dZoneManager to be initialized.

* Fix bugs

- Cannot delete from a RandomAccessIterator while in a range based for loop.

Touchup zone manager initialize

replace magic numbers with better named constants
replace magic zonecontrol id with a more readable hex alternative
condense stack variables
move initializers closer to their use
initialize entity manager with zone control

change initialize timings

If zone is not zero we expect to initialize the entity manager during zone manager initialization

Add constexpr for zone control LOT

* Add proper error handling

* revert vanity changes

* Update WorldServer.cpp

* Update dZoneManager.cpp
2023-07-15 13:56:33 -07:00

237 lines
7.8 KiB
C++

#include "dZoneManager.h"
#include "PetDigServer.h"
#include "MissionComponent.h"
#include "EntityManager.h"
#include "Character.h"
#include "PetComponent.h"
#include "User.h"
#include "eMissionState.h"
std::vector<LWOOBJID> PetDigServer::treasures{};
const DigInfo PetDigServer::defaultDigInfo = DigInfo{ 3495, -1, -1, false, false, false, false };
/**
* Summary of all the special treasure behaviors, indexed by their lot
*/
const std::map<LOT, DigInfo> PetDigServer::digInfoMap{
// Regular treasures
{3495, defaultDigInfo},
// Pet cove treasure
{7612, DigInfo { 7612, -1, -1, false, false, false, false }},
// Gnarled Forest flag treasure
{7410, DigInfo { 7410, -1, -1, false, true, false, false }},
// Gnarled Forest crab treasure
{9308, DigInfo { 9308, 7694, -1, false, false, false, false }},
// Avant Gardens mission treasure
{9307, DigInfo { 9307, -1, -1, false, true, false, true }},
// Avant Gardens bouncer treasure
{7559, DigInfo { 7559, -1, -1, false, false, true, false }},
// Crux Prime dragon treasure
{13098, DigInfo { 13098, 13067, 1298, false, false, false, false }},
// Bone treasure (can only be digged using the dragon)
{12192, DigInfo { 12192, -1, -1, true, false, false, false }},
};
void PetDigServer::OnStartup(Entity* self) {
treasures.push_back(self->GetObjectID());
const auto digInfoIterator = digInfoMap.find(self->GetLOT());
const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo;
// Reset any bouncers that might've been created by the previous dig
if (digInfo.bouncer) {
auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber"));
auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber);
auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber);
for (auto* bouncerSpawner : bouncerSpawners) {
for (auto* bouncer : bouncerSpawner->m_Info.nodes)
bouncerSpawner->Deactivate();
bouncerSpawner->Reset();
}
for (auto* switchSpawner : switchSpawners) {
switchSpawner->Deactivate();
switchSpawner->Reset();
}
}
}
void PetDigServer::OnDie(Entity* self, Entity* killer) {
const auto iterator = std::find(treasures.begin(), treasures.end(), self->GetObjectID());
if (iterator != treasures.end()) {
treasures.erase(iterator);
}
auto* owner = killer->GetOwner();
const auto digInfoIterator = digInfoMap.find(self->GetLOT());
const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo;
if (digInfo.spawnLot >= 0) {
PetDigServer::SpawnPet(self, owner, digInfo);
} else if (digInfo.builderOnly) {
// Some treasures may only be retrieved by the player that built the diggable
auto builder = self->GetVar<LWOOBJID>(u"builder"); // Set by the pet dig build script
if (builder != owner->GetObjectID())
return;
} else if (digInfo.xBuild) {
PetDigServer::HandleXBuildDig(self, owner, killer);
return;
} else if (digInfo.bouncer) {
PetDigServer::HandleBouncerDig(self, owner);
}
PetDigServer::ProgressPetDigMissions(owner, self);
self->SetNetworkVar<bool>(u"treasure_dug", true);
// TODO: Reset other pets
// Handles smashing leftovers (edge case for the AG X)
auto* xObject = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"X"));
if (xObject != nullptr) {
xObject->Smash(xObject->GetObjectID(), eKillType::VIOLENT);
}
}
void PetDigServer::HandleXBuildDig(const Entity* self, Entity* owner, Entity* pet) {
auto playerID = self->GetVar<LWOOBJID>(u"builder");
if (playerID == LWOOBJID_EMPTY || playerID != owner->GetObjectID())
return;
auto* playerEntity = Game::entityManager->GetEntity(playerID);
if (!playerEntity || !playerEntity->GetParentUser() || !playerEntity->GetParentUser()->GetLastUsedChar())
return;
auto* player = playerEntity->GetCharacter();
const auto groupID = self->GetVar<std::u16string>(u"groupID");
int32_t playerFlag = 0;
// The flag that the player dug up
if (groupID == u"Flag1") {
playerFlag = 61;
} else if (groupID == u"Flag2") {
playerFlag = 62;
} else if (groupID == u"Flag3") {
playerFlag = 63;
}
// If the player doesn't have the flag yet
if (playerFlag != 0 && !player->GetPlayerFlag(playerFlag)) {
auto* petComponent = pet->GetComponent<PetComponent>();
if (petComponent != nullptr) {
// TODO: Pet state = 9 ??
}
// Shows the flag object to the player
player->SetPlayerFlag(playerFlag, true);
}
auto* xObject = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"X"));
if (xObject != nullptr) {
xObject->Smash(xObject->GetObjectID(), eKillType::VIOLENT);
}
}
void PetDigServer::HandleBouncerDig(const Entity* self, const Entity* owner) {
auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber"));
auto bouncerSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncer" + bounceNumber);
auto switchSpawners = dZoneManager::Instance()->GetSpawnersByName("PetBouncerSwitch" + bounceNumber);
for (auto* bouncerSpawner : bouncerSpawners) {
bouncerSpawner->Activate();
}
for (auto* switchSpawner : switchSpawners) {
switchSpawner->Activate();
}
}
/**
* Progresses the Can You Dig It mission and the Pet Excavator Achievement if the player has never completed it yet
* \param owner the owner that just made a pet dig something up
*/
void PetDigServer::ProgressPetDigMissions(const Entity* owner, const Entity* chest) {
auto* missionComponent = owner->GetComponent<MissionComponent>();
if (missionComponent != nullptr) {
// Can You Dig It progress
const auto digMissionState = missionComponent->GetMissionState(843);
if (digMissionState == eMissionState::ACTIVE) {
missionComponent->ForceProgress(843, 1216, 1);
}
// Pet Excavator progress
const auto excavatorMissionState = missionComponent->GetMissionState(505);
if (excavatorMissionState == eMissionState::ACTIVE) {
if (chest->HasVar(u"PetDig")) {
int32_t playerFlag = 1260 + chest->GetVarAs<int32_t>(u"PetDig");
Character* player = owner->GetCharacter();
// check if player flag is set
if (!player->GetPlayerFlag(playerFlag)) {
missionComponent->ForceProgress(505, 767, 1);
player->SetPlayerFlag(playerFlag, 1);
}
}
}
}
}
/**
* Some treasures spawn special pets, this handles that case
* \param owner the owner that just made a pet dig something up
* \param digInfo information regarding the treasure, will also contain info about the pet to spawn
*/
void PetDigServer::SpawnPet(Entity* self, const Entity* owner, const DigInfo digInfo) {
// Some treasures require a mission to be active
if (digInfo.requiredMission >= 0) {
auto* missionComponent = owner->GetComponent<MissionComponent>();
if (missionComponent != nullptr && missionComponent->GetMissionState(digInfo.requiredMission) < eMissionState::ACTIVE) {
return;
}
}
EntityInfo info{};
info.lot = digInfo.spawnLot;
info.pos = self->GetPosition();
info.rot = self->GetRotation();
info.spawnerID = self->GetSpawnerID();
info.settings = {
new LDFData<LWOOBJID>(u"tamer", owner->GetObjectID()),
new LDFData<std::string>(u"group", "pet" + std::to_string(owner->GetObjectID())),
new LDFData<std::string>(u"spawnAnim", "spawn-pet"),
new LDFData<float>(u"spawnTimer", 1.0)
};
auto* spawnedPet = Game::entityManager->CreateEntity(info);
Game::entityManager->ConstructEntity(spawnedPet);
}
Entity* PetDigServer::GetClosestTresure(NiPoint3 position) {
float closestDistance = 0;
Entity* closest = nullptr;
for (const auto tresureId : treasures) {
auto* tresure = Game::entityManager->GetEntity(tresureId);
if (tresure == nullptr) continue;
float distance = Vector3::DistanceSquared(tresure->GetPosition(), position);
if (closest == nullptr || distance < closestDistance) {
closestDistance = distance;
closest = tresure;
}
}
return closest;
}