Skip to content

bugfix(audio): Fix particle cannon being inaudible after saveload#2302

Open
stephanmeesters wants to merge 2 commits intoTheSuperHackers:mainfrom
stephanmeesters:bigfix-particlecannon-audio
Open

bugfix(audio): Fix particle cannon being inaudible after saveload#2302
stephanmeesters wants to merge 2 commits intoTheSuperHackers:mainfrom
stephanmeesters:bigfix-particlecannon-audio

Conversation

@stephanmeesters
Copy link

@stephanmeesters stephanmeesters commented Feb 13, 2026

Fixes issue where sound from the particle cannon is not audible after saveload.

A savegame can be made during any of combinations of STATUS_ and LASERSTATUS_ below. Sounds are triggered only during state change, so when loading a savegame any of the sounds in the Active column need to be added.

Tested with a savegame for each STATUS_.

Repeating sequence of the particle cannon

STATUS_ LASERSTATUS_ Add sound Clear sound Active sound
PACKING (1) NONE none none none
CHARGING NONE powerupSound unpackToReadySound
firingToIdleSound
annihilationSound
powerupSound
PREPARING NONE unpackToReadySound firingToIdleSound
annihilationSound
powerupSound
unpackToReadySound
ALMOST_READY NONE none none powerupSound
unpackToReadySound
READY_TO_FIRE NONE none powerupSound
firingToIdleSound
annihilationSound
unpackToReadySound
PREFIRE NONE none none unpackToReadySound
FIRING NONE
BORN
firingToIdleSound
annihilationSound¹
powerupSound
unpackToReadySound
firingToIdleSound
annihilationSound
POSTFIRE BORN none none firingToIdleSound
annihilationSound
PACKING (2) DECAYING
DEAD
none annihilationSound² firingToIdleSound
annihilationSound
IDLE NONE none powerupSound
unpackToReadySound
firingToIdleSound
annihilationSound
none

¹ Sound added at LASERSTATUS_BORN
² Sound cleared at LASERSTATUS_DEAD

PACKING appears twice for some reason.

Status meanings

  • PACKING (1): Particle cannon is inactive and fully reset. Idle state.
  • CHARGING: Early pre-ready phase; charging loop plays.
  • PREPARING: Antenna/deploy preparation phase.
  • ALMOST_READY: Near-ready phase before final ready state.
  • READY_TO_FIRE: Weapon is available and waiting for fire command.
  • PREFIRE: Transitional pre-shot state (defined and checked, typically brief/rare in this flow).
  • FIRING: Main active attack phase while beam is operating.
  • POSTFIRE: Attack is decaying after firing window ends.
  • PACKING (2): Pack-up phase after attack/ready path.
  • IDLE: Another form of idle, used to reset audio, lasts very short.

Laser status meanings

  • NONE: No orbital beam lifecycle started yet for current cycle.
  • BORN: Orbit-to-target beam was created and is in active phase.
  • DECAYING: Beam is in decay/shutdown window.
  • DEAD: Beam lifecycle is finished (end state before reset to NONE on next cycle setup).

Sound meanings

  • powerupSound: Charge, at particle cannon.
  • unpackToReadySound: Prep, at particle cannon.
  • firingToIdleSound: Firing/packing, at particle cannon.
  • annihilationSound: Beam-impact, at origin beam.

Todo

  • Replicate to Generals

@greptile-apps
Copy link

greptile-apps bot commented Feb 13, 2026

Greptile Overview

Greptile Summary

Restored particle cannon sound playback after saveload by re-creating audio events in loadPostProcess() based on the saved state. The fix implements conditional sound restoration for four sound types (powerupSound, unpackToReadySound, firingToIdleSound, annihilationSound) across all possible STATUS_ and LASERSTATUS_ combinations.

  • Added sound restoration matching the state table documented in the PR description
  • Follows existing patterns from setLogicalStatus() and createOrbitToTargetLaser()
  • Includes proper null checks for event names and drawable IDs
  • Correctly uses setObjectID() for cannon-positioned sounds and setDrawableID() for beam-positioned sounds

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation correctly matches the documented state table, follows existing code patterns for audio management, includes proper validation checks, and addresses a well-defined bug without introducing new logic paths or modifying existing behavior
  • No files require special attention

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ParticleUplinkCannonUpdate.cpp Added sound restoration logic in loadPostProcess() to fix missing particle cannon sounds after saveload, correctly implementing state-based sound activation

Last reviewed commit: 169ce11


// TheSuperHackers @info stephanmeesters 13/02/2026
// Fix issue where sound from the particle cannon is not audible after saveload
if( m_status == STATUS_FIRING || m_status == STATUS_POSTFIRE || m_status == STATUS_PACKING )
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why POSTFIRE and PACKING ?

Can you explain how the statuses relate to the lifetime of the 2 sounds?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a table of all possible states and all associated sounds, tried to keep this as simple as possible. More code was added for some other sounds I missed and handling of PACKING which appears twice in the sequence

Copy link

@xezon xezon Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work. Wow that is complicated.

@xezon xezon added Bug Something is not working right, typically is user facing Audio Is audio related Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Saveload Is Saveload/Xfer related labels Feb 14, 2026
}

if ( m_status == STATUS_FIRING || m_status == STATUS_POSTFIRE ||
(m_status == STATUS_PACKING && (m_laserStatus == LASERSTATUS_DECAYING || m_laserStatus == LASERSTATUS_DEAD)) )
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really difficult to maintain correctness, because it needs to manually mirror the logic correctly and when the audio logic changes then this code would need to be adapted again, which then carries the risk of creating new bugs.

Instead, I suggest adding an Xfer function to AudioEventRTS and handle the state save/load in there for all possibilities. This will not work for legacy save files, but going forward it should be much simpler to maintain and be robust for any logic changes.

This also means that Xfer can be used for other module sounds as well. I expect Particle Cannon is not the only object that has this audio issue. But it is very obvious for it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a much better solution.

Perhaps keep this code but put it behind RETAIL_COMPATIBLE_CRC or similar, so we know to drop it after breaking compatibility?

Copy link

@xezon xezon Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With RETAIL_COMPATIBLE_XFER_SAVE old Xfer version, if we think it is worth it? I would personally not bother with the legacy saves, but since you already did all this work...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Audio Is audio related Bug Something is not working right, typically is user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker Saveload Is Saveload/Xfer related ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Particle Cannon Sound is not audible after saveload

2 participants