fix: Crux Prime dropship computer respawns and no longer crashes

The dropship computer's OnDie activated the "next" spawner network
(pipe number + 1) when a player smashed it and only fell back to the
first network otherwise. The computer has no next network, so once a
player smashed it (easiest with area attacks like the Doom Hammer) it
never came back. The live script (L_DROPSHIP_COMPUTER.lua, shipped in
the client's server scripts) always resets its own network and
activates the first one, which is what it does now.

OnUse also dereferenced GetMission(979) without a null check, crashing
the world when a player without that mission used the built computer.
It now matches the live script: only players with the mission active
get the Nexus Talon data card, once. SsModularBuildServer had the same
unchecked GetMission and now checks the mission state.

Fixes #596

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-26 18:42:25 -05:00
parent 040d7ec067
commit b316686538
2 changed files with 9 additions and 27 deletions

View File

@@ -19,7 +19,8 @@ void AmDropshipComputer::OnUse(Entity* self, Entity* user) {
if (!missionComponent || !inventoryComponent) return;
if (inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0 || missionComponent->GetMission(979)->GetMissionState() == eMissionState::COMPLETE) {
// Only players on the mission get the data card, and only once.
if (missionComponent->GetMissionState(979) != eMissionState::ACTIVE || inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0) {
return;
}
@@ -27,15 +28,10 @@ void AmDropshipComputer::OnUse(Entity* self, Entity* user) {
}
void AmDropshipComputer::OnDie(Entity* self, Entity* killer) {
// Reset this computer's spawner network and start the first one again, however it died.
const auto myGroup = GeneralUtils::UTF16ToWTF8(self->GetVar<std::u16string>(u"spawner_name"));
const auto pipeNum = GeneralUtils::TryParse<int32_t>(myGroup.substr(10, 1));
if (!pipeNum) return;
const auto pipeGroup = myGroup.substr(0, 10);
const auto nextPipeNum = pipeNum.value() + 1;
const auto samePipeSpawners = Game::zoneManager->GetSpawnersByName(myGroup);
if (!samePipeSpawners.empty()) {
@@ -44,22 +40,10 @@ void AmDropshipComputer::OnDie(Entity* self, Entity* killer) {
samePipeSpawners[0]->Deactivate();
}
if (killer != nullptr && killer->IsPlayer()) {
const auto nextPipe = pipeGroup + std::to_string(nextPipeNum);
const auto firstPipeSpawners = Game::zoneManager->GetSpawnersByName(pipeGroup + "1");
const auto nextPipeSpawners = Game::zoneManager->GetSpawnersByName(nextPipe);
if (!nextPipeSpawners.empty()) {
nextPipeSpawners[0]->Activate();
}
} else {
const auto nextPipe = pipeGroup + "1";
const auto firstPipeSpawners = Game::zoneManager->GetSpawnersByName(nextPipe);
if (!firstPipeSpawners.empty()) {
firstPipeSpawners[0]->Activate();
}
if (!firstPipeSpawners.empty()) {
firstPipeSpawners[0]->Activate();
}
}

View File

@@ -1,16 +1,14 @@
#include "SsModularBuildServer.h"
#include "MissionComponent.h"
#include "eMissionState.h"
#include "eReplicaComponentType.h"
void SsModularBuildServer::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) {
int missionNum = 1732;
if (bCompleted) {
MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION));
Mission* rocketMission = mission->GetMission(missionNum);
if (rocketMission->GetMissionState() == eMissionState::ACTIVE) {
auto* const mission = player->GetComponent<MissionComponent>();
// The player may never have had this mission, so check the state instead of the mission itself.
if (mission && mission->GetMissionState(missionNum) == eMissionState::ACTIVE) {
mission->ForceProgress(missionNum, 2478, 1);
}
}