2022-07-05 06:00:10 +00:00
|
|
|
#include "dZoneManager.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
#include "PetDigServer.h"
|
2023-11-19 02:11:28 +00:00
|
|
|
#include "DestroyableComponent.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
#include "MissionComponent.h"
|
|
|
|
#include "EntityManager.h"
|
|
|
|
#include "Character.h"
|
|
|
|
#include "PetComponent.h"
|
2023-01-07 05:17:05 +00:00
|
|
|
#include "User.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
#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 }},
|
|
|
|
};
|
|
|
|
|
2022-02-05 12:19:25 +00:00
|
|
|
void PetDigServer::OnStartup(Entity* self) {
|
2021-12-05 17:54:36 +00:00
|
|
|
treasures.push_back(self->GetObjectID());
|
|
|
|
const auto digInfoIterator = digInfoMap.find(self->GetLOT());
|
|
|
|
const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// 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"));
|
2023-07-17 22:55:33 +00:00
|
|
|
auto bouncerSpawners = Game::zoneManager->GetSpawnersByName("PetBouncer" + bounceNumber);
|
|
|
|
auto switchSpawners = Game::zoneManager->GetSpawnersByName("PetBouncerSwitch" + bounceNumber);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
for (auto* bouncerSpawner : bouncerSpawners) {
|
|
|
|
for (auto* bouncer : bouncerSpawner->m_Info.nodes)
|
|
|
|
bouncerSpawner->Deactivate();
|
|
|
|
bouncerSpawner->Reset();
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
for (auto* switchSpawner : switchSpawners) {
|
|
|
|
switchSpawner->Deactivate();
|
|
|
|
switchSpawner->Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-05 12:19:25 +00:00
|
|
|
void PetDigServer::OnDie(Entity* self, Entity* killer) {
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto iterator = std::find(treasures.begin(), treasures.end(), self->GetObjectID());
|
|
|
|
if (iterator != treasures.end()) {
|
|
|
|
treasures.erase(iterator);
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* owner = killer->GetOwner();
|
|
|
|
const auto digInfoIterator = digInfoMap.find(self->GetLOT());
|
|
|
|
const auto digInfo = digInfoIterator != digInfoMap.end() ? digInfoIterator->second : defaultDigInfo;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
if (digInfo.spawnLot >= 0) {
|
|
|
|
PetDigServer::SpawnPet(self, owner, digInfo);
|
|
|
|
} else if (digInfo.builderOnly) {
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// 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);
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2022-02-05 12:19:25 +00:00
|
|
|
PetDigServer::ProgressPetDigMissions(owner, self);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
self->SetNetworkVar<bool>(u"treasure_dug", true);
|
|
|
|
// TODO: Reset other pets
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// Handles smashing leftovers (edge case for the AG X)
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* xObject = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"X"));
|
2021-12-05 17:54:36 +00:00
|
|
|
if (xObject != nullptr) {
|
2023-05-02 22:39:21 +00:00
|
|
|
xObject->Smash(xObject->GetObjectID(), eKillType::VIOLENT);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-19 00:43:47 +00:00
|
|
|
void PetDigServer::OnUse(Entity* self, Entity* user) {
|
2023-12-14 07:33:49 +00:00
|
|
|
LOG_DEBUG("Treasure used! LWOOBJID: %d", self->GetObjectID());
|
2023-11-19 00:43:47 +00:00
|
|
|
|
|
|
|
auto* petComponent = PetComponent::GetActivePet(user->GetObjectID());
|
|
|
|
if (!petComponent) return;
|
|
|
|
|
2023-12-14 07:33:49 +00:00
|
|
|
if(petComponent->IsReadyToInteract()) {
|
2023-12-13 06:14:53 +00:00
|
|
|
petComponent->StartInteractTreasureDig();
|
2023-11-19 00:43:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
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;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* playerEntity = Game::entityManager->GetEntity(playerID);
|
2024-02-04 14:29:05 +00:00
|
|
|
if (!playerEntity || !playerEntity->GetCharacter())
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* player = playerEntity->GetCharacter();
|
|
|
|
const auto groupID = self->GetVar<std::u16string>(u"groupID");
|
2023-05-02 22:39:21 +00:00
|
|
|
int32_t playerFlag = 0;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// 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 ??
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// Shows the flag object to the player
|
|
|
|
player->SetPlayerFlag(playerFlag, true);
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* xObject = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"X"));
|
2021-12-05 17:54:36 +00:00
|
|
|
if (xObject != nullptr) {
|
2023-05-02 22:39:21 +00:00
|
|
|
xObject->Smash(xObject->GetObjectID(), eKillType::VIOLENT);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PetDigServer::HandleBouncerDig(const Entity* self, const Entity* owner) {
|
|
|
|
auto bounceNumber = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"BouncerNumber"));
|
2023-07-17 22:55:33 +00:00
|
|
|
auto bouncerSpawners = Game::zoneManager->GetSpawnersByName("PetBouncer" + bounceNumber);
|
|
|
|
auto switchSpawners = Game::zoneManager->GetSpawnersByName("PetBouncerSwitch" + bounceNumber);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
for (auto* bouncerSpawner : bouncerSpawners) {
|
|
|
|
bouncerSpawner->Activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto* switchSpawner : switchSpawners) {
|
|
|
|
switchSpawner->Activate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-02-05 12:19:25 +00:00
|
|
|
* Progresses the Can You Dig It mission and the Pet Excavator Achievement if the player has never completed it yet
|
2021-12-05 17:54:36 +00:00
|
|
|
* \param owner the owner that just made a pet dig something up
|
|
|
|
*/
|
2022-02-05 12:19:25 +00:00
|
|
|
void PetDigServer::ProgressPetDigMissions(const Entity* owner, const Entity* chest) {
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* missionComponent = owner->GetComponent<MissionComponent>();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
if (missionComponent != nullptr) {
|
2022-02-05 12:19:25 +00:00
|
|
|
// Can You Dig It progress
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto digMissionState = missionComponent->GetMissionState(843);
|
|
|
|
if (digMissionState == eMissionState::ACTIVE) {
|
|
|
|
missionComponent->ForceProgress(843, 1216, 1);
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2022-02-05 12:19:25 +00:00
|
|
|
// 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();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2022-02-05 12:19:25 +00:00
|
|
|
// check if player flag is set
|
|
|
|
if (!player->GetPlayerFlag(playerFlag)) {
|
|
|
|
missionComponent->ForceProgress(505, 767, 1);
|
|
|
|
player->SetPlayerFlag(playerFlag, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
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)
|
|
|
|
};
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* spawnedPet = Game::entityManager->CreateEntity(info);
|
|
|
|
Game::entityManager->ConstructEntity(spawnedPet);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 12:19:25 +00:00
|
|
|
Entity* PetDigServer::GetClosestTresure(NiPoint3 position) {
|
2021-12-05 17:54:36 +00:00
|
|
|
float closestDistance = 0;
|
|
|
|
Entity* closest = nullptr;
|
|
|
|
|
|
|
|
for (const auto tresureId : treasures) {
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* tresure = Game::entityManager->GetEntity(tresureId);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
if (tresure == nullptr) continue;
|
|
|
|
|
|
|
|
float distance = Vector3::DistanceSquared(tresure->GetPosition(), position);
|
2022-02-05 12:19:25 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
if (closest == nullptr || distance < closestDistance) {
|
|
|
|
closestDistance = distance;
|
|
|
|
closest = tresure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return closest;
|
|
|
|
}
|