mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 19:03:43 +00:00
Issue 536. A pet that reached a pet switch jumped on it by itself for free. Now it works like digs, following what live did (2014 captures): on the way the pet has state 0x500 and the owner gets PR_BOUNCER_TUTORIAL_01; on the switch the pet has state 0x120 and the Jump On Object ability, plays "excited" while the switch plays "engaged", and the owner gets the pet action button (ShowPetActionButton 2) and PR_BOUNCER_TUTORIAL_03. Using it costs PetAbilities.ImaginationCost (2), the pet plays "jump", the owner gets PR_TOOLTIP_1ST_PET_JUMPED_ON_SWITCH and the switch turns its bouncer on. The switch plays "launch" then, as on live, instead of "engaged". The pet switch is no longer written into the pet's serialized interaction (it was never cleared). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
158 lines
4.1 KiB
C++
158 lines
4.1 KiB
C++
#include "SwitchComponent.h"
|
|
#include "EntityManager.h"
|
|
#include "eTriggerEventType.h"
|
|
#include "RenderComponent.h"
|
|
#include "DestroyableComponent.h"
|
|
#include "EffectsMessages.h"
|
|
|
|
std::vector<SwitchComponent*> SwitchComponent::petSwitches;
|
|
|
|
SwitchComponent::SwitchComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) {
|
|
m_Active = false;
|
|
|
|
m_ResetTime = m_Parent->GetVarAs<int32_t>(u"switch_reset_time");
|
|
|
|
m_QuickBuild = m_Parent->GetComponent<QuickBuildComponent>();
|
|
|
|
const auto factions = GeneralUtils::SplitString(m_Parent->GetVar<std::u16string>(u"respond_to_faction"), u':');
|
|
for (const auto& faction : factions) {
|
|
auto factionID = GeneralUtils::TryParse<int32_t>(GeneralUtils::UTF16ToWTF8(faction));
|
|
if (!factionID) continue;
|
|
m_FactionsToRespondTo.push_back(factionID.value());
|
|
}
|
|
}
|
|
|
|
SwitchComponent::~SwitchComponent() {
|
|
const auto& iterator = std::find(petSwitches.begin(), petSwitches.end(), this);
|
|
|
|
if (iterator != petSwitches.end()) {
|
|
petSwitches.erase(iterator);
|
|
}
|
|
}
|
|
|
|
void SwitchComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
|
outBitStream.Write(m_Active);
|
|
}
|
|
|
|
void SwitchComponent::OnUse(Entity* originator) {
|
|
const auto* const destroyableComponent = originator->GetComponent<DestroyableComponent>();
|
|
if (!destroyableComponent) return;
|
|
for (const auto faction : m_FactionsToRespondTo) {
|
|
if (destroyableComponent->HasFaction(faction)) {
|
|
EntityEnter(originator);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SwitchComponent::SetActive(bool active) {
|
|
m_Active = active;
|
|
|
|
if (m_PetBouncer != nullptr) {
|
|
m_PetBouncer->SetPetBouncerEnabled(active);
|
|
}
|
|
}
|
|
|
|
bool SwitchComponent::GetActive() const {
|
|
return m_Active;
|
|
}
|
|
|
|
void SwitchComponent::EntityEnter(Entity* entity) {
|
|
if (!m_Active) {
|
|
if (m_QuickBuild) {
|
|
if (m_QuickBuild->GetState() != eQuickBuildState::COMPLETED) return;
|
|
}
|
|
m_Active = true;
|
|
if (!m_Parent) return;
|
|
m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity);
|
|
|
|
const auto grpName = m_Parent->GetVarAsString(u"grp_name");
|
|
|
|
if (!grpName.empty()) {
|
|
const auto entities = Game::entityManager->GetEntitiesInGroup(grpName);
|
|
|
|
for (auto* entity : entities) {
|
|
entity->OnFireEventServerSide(entity, "OnActivated");
|
|
}
|
|
}
|
|
|
|
m_Timer = m_ResetTime;
|
|
|
|
if (m_PetBouncer != nullptr) {
|
|
GameMessages::PlayFXEffect(m_Parent->GetObjectID(), 2602, u"pettriggeractive", "BounceEffect").Send(UNASSIGNED_SYSTEM_ADDRESS);
|
|
// Live played "launch" here; "engaged" is played when a pet arrives on the switch
|
|
RenderComponent::PlayAnimation(m_Parent, u"launch");
|
|
m_PetBouncer->SetPetBouncerEnabled(true);
|
|
} else {
|
|
Game::entityManager->SerializeEntity(m_Parent);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void SwitchComponent::EntityLeave(Entity* entity) {
|
|
|
|
}
|
|
|
|
void SwitchComponent::Update(float deltaTime) {
|
|
if (m_Active) {
|
|
m_Timer -= deltaTime;
|
|
|
|
if (m_Timer <= 0.0f) {
|
|
m_Active = false;
|
|
if (!m_Parent) return;
|
|
m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent);
|
|
|
|
const auto grpName = m_Parent->GetVarAsString(u"grp_name");
|
|
|
|
if (!grpName.empty()) {
|
|
const auto entities = Game::entityManager->GetEntitiesInGroup(grpName);
|
|
|
|
for (auto* entity : entities) {
|
|
entity->OnFireEventServerSide(entity, "OnDectivated");
|
|
}
|
|
}
|
|
|
|
if (m_PetBouncer != nullptr) {
|
|
m_PetBouncer->SetPetBouncerEnabled(false);
|
|
} else {
|
|
Game::entityManager->SerializeEntity(m_Parent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Entity* SwitchComponent::GetParentEntity() const {
|
|
return m_Parent;
|
|
}
|
|
|
|
SwitchComponent* SwitchComponent::GetClosestSwitch(NiPoint3 position) {
|
|
float closestDistance = 0;
|
|
SwitchComponent* closest = nullptr;
|
|
|
|
for (SwitchComponent* petSwitch : petSwitches) {
|
|
float distance = Vector3::DistanceSquared(petSwitch->m_Parent->GetPosition(), position);
|
|
|
|
if (closest == nullptr || distance < closestDistance) {
|
|
closestDistance = distance;
|
|
closest = petSwitch;
|
|
}
|
|
}
|
|
|
|
return closest;
|
|
}
|
|
|
|
|
|
void SwitchComponent::SetPetBouncer(BouncerComponent* value) {
|
|
m_PetBouncer = value;
|
|
|
|
if (value != nullptr) {
|
|
m_PetBouncer->SetPetEnabled(true);
|
|
petSwitches.push_back(this);
|
|
}
|
|
}
|
|
|
|
BouncerComponent* SwitchComponent::GetPetBouncer() const {
|
|
return m_PetBouncer;
|
|
}
|