Skip to content

Fix public quest stages failing to spawn, hanging, and showing a 0.00 reset timer - #176

Open
Chris443C wants to merge 1 commit into
Shmerrick:masterfrom
Chris443C:fix/pq-spawn-loop-abort
Open

Fix public quest stages failing to spawn, hanging, and showing a 0.00 reset timer#176
Chris443C wants to merge 1 commit into
Shmerrick:masterfrom
Chris443C:fix/pq-spawn-loop-abort

Conversation

@Chris443C

Copy link
Copy Markdown

Four related fixes to the public quest system, found while bringing a local server up against the published database.

1. PQuestObjective.Reset() — one bad row aborts the whole stage

When a Type 2 spawn's gameobject proto was missing, the method returned instead of skipping the row. Spawns are iterated in list order, so a single unknown entry silently prevented every creature listed after it from spawning.

The visible symptom is a stage that comes up with a partial mob set, no in-game error, and no corpses — including cases where the mob required to complete the stage is the one that never appears. The Type 1 branch immediately above already used continue for the equivalent case; this makes the two consistent.

The log line now names the entry and objective, so the underlying data gap is diagnosable rather than silent.

2. PublicQuest.AdvanceToNextStage()QUEST_PROTECT_UNIT stages could hang forever

Protect stages were excluded from arming the Failed event. If the protected unit died, the stage could neither complete — credit comes from PQuestCreature.Protected(), which never fires once the unit is dead — nor time out. The quest stayed stuck until a GM ran .pq reset.

The timer can't simply be armed at Stage.Time: PQuestStage.Time is copied from PQuest_Objective.Time in the constructor, which is the same value the protect credit fires on, so arming it there makes failure race completion at the identical instant. PROTECT_FAIL_GRACE turns it into a backstop so a surviving unit always wins.

3. PublicQuest.Failed() — client showed "resetting in 0.00"

Failed() scheduled Reset correctly but never refreshed _stageTimeEnd, which is what SendCurrentStage renders as the countdown. End() already does this. Without it the field still held the already-elapsed stage deadline, so the client displayed 0.00 for the entire TIME_PQ_RESET wait. Behaviour was correct; only the display was wrong.

4. KeepCommunications.SendKeepStatus() — NRE during startup keep locking

innerDoor.GameObject is only created once a door is spawned into its region, so it is null while keeps are locked at startup. innerDoor was already null-checked; this extends the guard to its GameObject.

Testing

Verified on a local server against the published war_world dump:

  • Before: PQ 165 (Raven Host Vanguard) stage II spawned 8 of 20 creatures, omitting Father Sigwald — the protected unit — because two Type 2 entries earlier in its list have no gameobject proto. The stage was unwinnable.
  • After: the full spawn set appears and the stage completes normally.
  • Failure path exercised by letting the protected unit die: the stage now fails and resets with a correct countdown instead of hanging.

Changes are limited to those four sites; no configuration or data files are included.

🤖 Generated with Claude Code

… timer

PQuestObjective.Reset(): a missing gameobject proto returned out of the whole
method instead of skipping the row. Spawns are processed in list order, so one
unknown Type 2 entry silently prevented every creature listed after it from
spawning - producing stages that come up with a partial mob set and no error
visible in game. The Type 1 branch already used continue for the equivalent
case; this makes the two consistent. The log line now names the entry and
objective so the underlying data gap is diagnosable.

PublicQuest.AdvanceToNextStage(): QUEST_PROTECT_UNIT stages were skipped when
arming the Failed event, so if the protected unit died the stage could neither
complete (credit comes from PQuestCreature.Protected(), which never fires once
the unit is dead) nor time out - the quest hung until a GM reset it. The timer
cannot simply be armed at Stage.Time, because PQuestStage.Time is copied from
PQuest_Objective.Time, the same value the protect credit fires on, which would
make failure race completion at the identical instant. PROTECT_FAIL_GRACE makes
it a backstop so a surviving unit always wins.

PublicQuest.Failed(): scheduled Reset correctly but never refreshed
_stageTimeEnd, which is what SendCurrentStage renders as the countdown. End()
already does this. Without it the client displayed "resetting in 0.00" for the
full TIME_PQ_RESET wait.

KeepCommunications.SendKeepStatus(): guard innerDoor.GameObject, which is only
created once a door is spawned into its region and is therefore null during
startup keep locking.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant