@@ -212,16 +212,16 @@ void ParticleUplinkCannonUpdate::killEverything()
212212 removeAllEffects ();
213213
214214 // This laser is independent from the other effects and needs to be specially handled.
215- if ( m_orbitToTargetBeamID )
215+ if ( m_orbitToTargetBeamID != INVALID_DRAWABLE_ID )
216216 {
217217 Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
218218 if ( beam )
219219 {
220220 TheGameClient->destroyDrawable ( beam );
221221 }
222222 m_orbitToTargetBeamID = INVALID_DRAWABLE_ID ;
223- m_orbitToTargetLaserRadius = LaserRadiusUpdate ();
224223 }
224+ m_orbitToTargetLaserRadius = LaserRadiusUpdate ();
225225
226226 TheAudio->removeAudioEvent ( m_powerupSound.getPlayingHandle () );
227227 TheAudio->removeAudioEvent ( m_unpackToReadySound.getPlayingHandle () );
@@ -457,40 +457,43 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update()
457457 break ;
458458 case LASERSTATUS_BORN :
459459 {
460- Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
461- if ( beam )
460+ if ( orbitalDecayStart <= now )
462461 {
463- // m_annihilationSound.setPosition( beam->getPosition() );
464- if ( orbitalDecayStart <= now )
462+ Drawable * beam = TheGameClient-> findDrawableByID ( m_orbitToTargetBeamID );
463+ if ( beam )
465464 {
465+ // m_annihilationSound.setPosition( beam->getPosition() );
466466 static NameKeyType nameKeyClientUpdate = NAMEKEY ( " LaserUpdate" );
467467 LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule ( nameKeyClientUpdate );
468468 if ( update )
469469 {
470470 update->setDecayFrames ( data->m_widthGrowFrames );
471- m_orbitToTargetLaserRadius.setDecayFrames ( data->m_widthGrowFrames );
472471 }
473- m_laserStatus = LASERSTATUS_DECAYING ;
474472 }
473+ m_orbitToTargetLaserRadius.setDecayFrames ( data->m_widthGrowFrames );
474+ m_laserStatus = LASERSTATUS_DECAYING ;
475475 }
476476 break ;
477477 }
478478 case LASERSTATUS_DECAYING :
479479 {
480- Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
481- if ( beam )
480+ if ( orbitalDeathFrame <= now )
482481 {
483- // m_annihilationSound.setPosition( beam->getPosition() );
484482 TheAudio->removeAudioEvent ( m_annihilationSound.getPlayingHandle () );
485- if ( orbitalDeathFrame <= now )
483+ if ( m_orbitToTargetBeamID != INVALID_DRAWABLE_ID )
486484 {
487- TheGameClient->destroyDrawable ( beam );
485+ Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
486+ if ( beam )
487+ {
488+ // m_annihilationSound.setPosition( beam->getPosition() );
489+ TheGameClient->destroyDrawable ( beam );
490+ }
488491 m_orbitToTargetBeamID = INVALID_DRAWABLE_ID ;
489- m_orbitToTargetLaserRadius = LaserRadiusUpdate ();
490- m_laserStatus = LASERSTATUS_DEAD ;
491- m_startAttackFrame = 0 ;
492- setLogicalStatus ( STATUS_IDLE );
493492 }
493+ m_orbitToTargetLaserRadius = LaserRadiusUpdate ();
494+ m_laserStatus = LASERSTATUS_DEAD ;
495+ m_startAttackFrame = 0 ;
496+ setLogicalStatus ( STATUS_IDLE );
494497 }
495498 break ;
496499 }
@@ -499,8 +502,13 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update()
499502 break ;
500503 }
501504
502- Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
503- if ( beam && orbitalBirthFrame <= now && now <= orbitalDeathFrame )
505+ #if RETAIL_COMPATIBLE_CRC
506+ // TheSuperHackers @info helmutbuhler 12/06/2025
507+ // Note that this code is very brittle for retail compatibility. Inlining isFiring
508+ // can cause incompatibility in some circumstances.
509+ #endif
510+ const Bool isFiring = orbitalBirthFrame <= now && now < orbitalDeathFrame;
511+ if ( isFiring )
504512 {
505513
506514 if ( !m_manualTargetMode && !m_scriptedWaypointMode )
@@ -609,27 +617,35 @@ UpdateSleepTime ParticleUplinkCannonUpdate::update()
609617
610618 Real scorchRadius = 0 .0f ;
611619 Real damageRadius = 0 .0f ;
620+ Real templateLaserRadius = 13 .0f ;
621+ Real visualLaserRadius = 0 .0f ;
612622
613623 // Reset the laser position
614- static NameKeyType nameKeyClientUpdate = NAMEKEY ( " LaserUpdate" );
615- LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule ( nameKeyClientUpdate );
616- if ( update )
624+ Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
625+ if ( beam )
617626 {
618- update->initLaser ( NULL , NULL , &orbitPosition, &m_currentTargetPosition, " " );
619- const Real visualLaserRadius = update->getCurrentLaserRadius ();
620- scorchRadius = visualLaserRadius * data->m_scorchMarkScalar ;
621-
622- // TheSuperHackers @refactor helmutbuhler/xezon 17/05/2025
623- // Originally the damage radius was calculated with a value updated by LaserUpdate::clientUpdate().
624- // To no longer rely on client updates, this class now maintains a logical copy of the visual laser radius.
625- m_orbitToTargetLaserRadius.updateRadius ();
626- const Real logicalLaserRadius = update->getTemplateLaserRadius () * m_orbitToTargetLaserRadius.getWidthScale ();
627- damageRadius = logicalLaserRadius * data->m_damageRadiusScalar ;
628- #if RETAIL_COMPATIBLE_XFER_CRC
629- DEBUG_ASSERTCRASH (logicalLaserRadius == visualLaserRadius,
630- (" ParticleUplinkCannonUpdate's laser radius does not match LaserUpdate's laser radius - will cause mismatch in VS6 retail compatible builds\n " ));
631- #endif
627+ static NameKeyType nameKeyClientUpdate = NAMEKEY ( " LaserUpdate" );
628+ LaserUpdate *update = (LaserUpdate*)beam->findClientUpdateModule ( nameKeyClientUpdate );
629+ if ( update )
630+ {
631+ update->initLaser ( NULL , NULL , &orbitPosition, &m_currentTargetPosition, " " );
632+ // TheSuperHackers @logic-client-separation The GameLogic has a dependency on this drawable.
633+ // The logical laser radius for the damage should probably be part of ParticleUplinkCannonUpdateModuleData.
634+ templateLaserRadius = update->getTemplateLaserRadius ();
635+ visualLaserRadius = update->getCurrentLaserRadius ();
636+ }
632637 }
638+ // TheSuperHackers @refactor helmutbuhler/xezon 17/05/2025
639+ // Originally the damageRadius was calculated with a value updated by LaserUpdate::clientUpdate.
640+ // To no longer rely on GameClient updates, this class now maintains a copy of the LaserRadiusUpdate.
641+ m_orbitToTargetLaserRadius.updateRadius ();
642+ const Real logicalLaserRadius = templateLaserRadius * m_orbitToTargetLaserRadius.getWidthScale ();
643+ damageRadius = logicalLaserRadius * data->m_damageRadiusScalar ;
644+ scorchRadius = logicalLaserRadius * data->m_scorchMarkScalar ;
645+ #if defined(RETAIL_COMPATIBLE_CRC)
646+ DEBUG_ASSERTCRASH (logicalLaserRadius == visualLaserRadius,
647+ (" ParticleUplinkCannonUpdate's laser radius does not match LaserUpdate's laser radius - will cause mismatch in VS6 retail compatible builds\n " ));
648+ #endif
633649
634650 // Create scorch marks periodically
635651 if ( m_nextScorchMarkFrame <= now )
@@ -988,13 +1004,15 @@ void ParticleUplinkCannonUpdate::createOrbitToTargetLaser( UnsignedInt growthFra
9881004{
9891005 const ParticleUplinkCannonUpdateModuleData *data = getParticleUplinkCannonUpdateModuleData ();
9901006
991- Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
992- if ( beam )
1007+ if ( m_orbitToTargetBeamID != INVALID_DRAWABLE_ID )
9931008 {
994- TheAudio->removeAudioEvent ( m_annihilationSound.getPlayingHandle () );
995- TheGameClient->destroyDrawable ( beam );
1009+ Drawable *beam = TheGameClient->findDrawableByID ( m_orbitToTargetBeamID );
1010+ if ( beam )
1011+ {
1012+ TheAudio->removeAudioEvent ( m_annihilationSound.getPlayingHandle () );
1013+ TheGameClient->destroyDrawable ( beam );
1014+ }
9961015 m_orbitToTargetBeamID = INVALID_DRAWABLE_ID ;
997- m_orbitToTargetLaserRadius = LaserRadiusUpdate ();
9981016 }
9991017
10001018 if ( data->m_particleBeamLaserName .isNotEmpty () )
@@ -1014,7 +1032,6 @@ void ParticleUplinkCannonUpdate::createOrbitToTargetLaser( UnsignedInt growthFra
10141032 orbitPosition.set ( &m_initialTargetPosition );
10151033 orbitPosition.z += 500 .0f ;
10161034 update->initLaser ( NULL , NULL , &orbitPosition, &m_initialTargetPosition, " " , growthFrames );
1017- m_orbitToTargetLaserRadius.initRadius ( growthFrames );
10181035 }
10191036 }
10201037 }
@@ -1025,6 +1042,9 @@ void ParticleUplinkCannonUpdate::createOrbitToTargetLaser( UnsignedInt growthFra
10251042 m_annihilationSound.setPlayingHandle ( TheAudio->addAudioEvent ( &m_annihilationSound ) );
10261043 }
10271044 }
1045+
1046+ m_orbitToTargetLaserRadius = LaserRadiusUpdate ();
1047+ m_orbitToTargetLaserRadius.initRadius ( growthFrames );
10281048}
10291049
10301050// -------------------------------------------------------------------------------------------------
0 commit comments