Merge remote-tracking branch 'upstream/main' into PetFixes

This commit is contained in:
jadebenn
2024-04-24 21:24:17 -05:00
6 changed files with 127 additions and 73 deletions

View File

@@ -4,6 +4,7 @@
#include "CDClientDatabase.h"
#include "CDPetAbilitiesTable.h"
#include "CDPetComponentTable.h"
#include "CDTamingBuildPuzzleTable.h"
#include "ChatPackets.h"
#include "EntityManager.h"
#include "Character.h"
@@ -37,7 +38,6 @@
#include "eMissionState.h"
#include "dNavMesh.h"
std::unordered_map<LOT, PetComponent::PuzzleData> PetComponent::buildCache{};
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
@@ -223,74 +223,37 @@ void PetComponent::StartTamingMinigame(Entity* originator) {
if (!inventoryComponent) return;
if (m_Preconditions.has_value() && !m_Preconditions->Check(originator, true)) return;
if (m_Preconditions.has_value() && !m_Preconditions->Check(originator, true)) {
return;
}
auto* const movementAIComponent = m_Parent->GetComponent<MovementAIComponent>();
if (movementAIComponent != nullptr) {
if (movementAIComponent) {
movementAIComponent->Stop();
}
inventoryComponent->DespawnPet();
const auto& cached = buildCache.find(m_Parent->GetLOT());
int32_t imaginationCost = 0;
std::string buildFile;
// It may make sense to move this minigame-specific logic into another file
if (cached == buildCache.end()) {
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;");
query.bind(1, static_cast<int>(m_Parent->GetLOT()));
auto result = query.execQuery();
if (result.eof()) {
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet.");
return;
}
if (result.fieldIsNull("ValidPiecesLXF")) {
result.finalize();
return;
}
buildFile = std::string(result.getStringField("ValidPiecesLXF"));
PuzzleData data{
.puzzleModelLot = result.getIntField("PuzzleModelLot"),
.buildFile = buildFile,
.timeLimit = static_cast<float>(result.getFloatField("Timelimit")),
.imaginationCost = result.getIntField("imagCostPerBuild"),
.numValidPieces = result.getIntField("NumValidPieces")
};
if (data.timeLimit <= 0) data.timeLimit = 60;
imaginationCost = data.imaginationCost;
buildCache[m_Parent->GetLOT()] = data;
result.finalize();
} else {
buildFile = cached->second.buildFile;
imaginationCost = cached->second.imaginationCost;
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
if (!entry) {
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet.");
return;
}
const auto* const destroyableComponent = originator->GetComponent<DestroyableComponent>();
if (!destroyableComponent) return;
if (!destroyableComponent) {
return;
}
const auto imagination = destroyableComponent->GetImagination();
if (imagination < entry->imaginationCost) {
return;
}
if (imagination < imaginationCost) return;
const auto& bricks = BrickDatabase::GetBricks(buildFile);
const auto& bricks = BrickDatabase::GetBricks(entry->validPieces);
if (bricks.empty()) {
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet.");
LOG("Couldn't find %s for minigame!", buildFile.c_str());
LOG("Couldn't find %s for minigame!", entry->validPieces.c_str());
return;
}
@@ -302,7 +265,6 @@ void PetComponent::StartTamingMinigame(Entity* originator) {
m_Parent->SetRotation(NiQuaternion::LookAt(petPosition, originatorPosition));
float interactionDistance = m_Parent->GetVar<float>(u"interaction_distance");
if (interactionDistance <= 0) {
interactionDistance = 15;
}
@@ -381,9 +343,8 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
return;
}
const auto& cached = buildCache.find(m_Parent->GetLOT());
if (cached == buildCache.end()) return;
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
if (!entry) return;
auto* const destroyableComponent = tamer->GetComponent<DestroyableComponent>();
@@ -391,14 +352,14 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
auto imagination = destroyableComponent->GetImagination();
imagination -= cached->second.imaginationCost;
imagination -= entry->imaginationCost;
destroyableComponent->SetImagination(imagination);
Game::entityManager->SerializeEntity(tamer);
if (clientFailed) {
if (imagination < cached->second.imaginationCost) {
if (imagination < entry->imaginationCost) {
ClientFailTamingMinigame();
}
} else {
@@ -421,17 +382,14 @@ void PetComponent::NotifyTamingBuildSuccess(const NiPoint3 position) {
return;
}
const auto& cached = buildCache.find(m_Parent->GetLOT());
if (cached == buildCache.end()) {
return;
}
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
if (!entry) return;
GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true);
RenderComponent::PlayAnimation(tamer, u"rebuild-celebrate");
EntityInfo info{};
info.lot = cached->second.puzzleModelLot;
info.lot = entry->puzzleModelLot;
info.pos = position;
info.rot = NiQuaternionConstant::IDENTITY;
info.spawnerID = tamer->GetObjectID();
@@ -627,13 +585,10 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
}
void PetComponent::StartTimer() {
const auto& cached = buildCache.find(m_Parent->GetLOT());
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
if (!entry) return;
if (cached == buildCache.end()) {
return;
}
m_Timer = cached->second.timeLimit;
m_Timer = entry->timeLimit;
}
void PetComponent::ClientFailTamingMinigame() {

View File

@@ -537,7 +537,7 @@ private:
/**
* Preconditions that need to be met before an entity can tame this pet
*/
std::optional<PreconditionExpression> m_Preconditions;
std::optional<PreconditionExpression> m_Preconditions{};
/**
* Pet information loaded from the CDClientDatabase