Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Core/GameEngine/Include/Common/CRCDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
void addCRCDumpLine(const char *fmt, ...);
void addCRCGenLine(const char *fmt, ...);
#define CRCDEBUG_LOG(x) addCRCDebugLine x
#define CRCDEBUG_LOG_NOCOUNTER(x) addCRCDebugLineNoCounter x
#define CRCDUMP_LOG(x) addCRCDumpLine x
#define CRCGEN_LOG(x) addCRCGenLine x

Expand Down Expand Up @@ -116,6 +117,7 @@
#define DUMPREALNAMED(x, y)

#define CRCDEBUG_LOG(x)
#define CRCDEBUG_LOG_NOCOUNTER(x)
#define CRCDUMP_LOG(x)
#define CRCGEN_LOG(x)

Expand Down
13 changes: 5 additions & 8 deletions Core/GameEngine/Include/GameClient/ParticleSys.h
Original file line number Diff line number Diff line change
Expand Up @@ -839,17 +839,14 @@ class ParticleSystemManager : public SubsystemInterface,

// TheSuperHackers @feature bobtista 31/01/2026
// ParticleSystemManager that does nothing. Used for Headless Mode.
// Generally does not load particle system templates. Certainly does not create particle systems.
// Does not render or update particles. Loads particle system templates.
class ParticleSystemManagerDummy : public ParticleSystemManager
{
public:
#if RETAIL_COMPATIBLE_CRC
// Must not overload init to keep loading the particle system templates,
// which are unfortunately needed to preserve the correct logic crc.
#else
virtual void init() override {}
virtual void reset() override {}
#endif
// TheSuperHackers @bugfix Okladnoj 29/07/2026 Must not overload init and reset, to keep loading the
// particle system templates. Game logic branches on template pointers, for example the gattling
// aim position in SpectreGunshipUpdate, so a headless client that skips them diverges in logic crc
// from a regular client. This applies with retail compatibility both enabled and disabled.
virtual void update() override {}

virtual Bool isDummy() const override { return true; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "Common/ThingTemplate.h"
#include "Common/RandomValue.h"
#include "Common/BitFlagsIO.h"
#include "Common/CRCDebug.h"

#include "GameLogic/AIPathfind.h"
#include "GameLogic/ExperienceTracker.h"
Expand Down Expand Up @@ -386,6 +387,11 @@ void MissileAIUpdate::detonate()

if (m_detonationWeaponTmpl)
{
// TheSuperHackers @info Okladnoj 30/07/2026 DieOnDetonate decides whether the projectile dies here
// or a frame later in doKillSelfState, which moves its die modules to a different frame. Record it,
// because a client that disagrees on this flag desyncs at the frame the projectile detonates.
CRCDEBUG_LOG_NOCOUNTER(("MissileAIUpdate::detonate() obj=%d weapon=%s dieOnDetonate=%d",
obj->getID(), m_detonationWeaponTmpl->getName().str(), m_detonationWeaponTmpl->getDieOnDetonate() ? 1 : 0));

TheWeaponStore->handleProjectileDetonation(m_detonationWeaponTmpl, obj, obj->getPosition(), m_extraBonusFlags, !m_noDamage );

Expand Down
14 changes: 14 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Weapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine

#include <string.h>

#define DEFINE_DEATH_NAMES
#define DEFINE_WEAPONBONUSCONDITION_NAMES
#define DEFINE_WEAPONBONUSFIELD_NAMES
Expand Down Expand Up @@ -1661,6 +1663,18 @@ WeaponTemplate *WeaponStore::newWeaponTemplate(AsciiString name)
WeaponTemplate *wt = newInstance(WeaponTemplate);
wt->m_name = name;
wt->m_nameKey = TheNameKeyGenerator->nameToKey( name );

if (strcmp(name.str(), "SupW_AuroraFuelBombWeapon") == 0)
{
// Note: m_dieOnDetonate is set to true to fix the Alpha Aurora second explosion inconsistency when targeting structures.
// SupW_AuroraFuelBombWeapon does not specify MissileCallsOnDie in INI, so getDieOnDetonate()
// returned false, causing detonate() to skip attemptDamage() which is what triggers die modules.
// When INI is editable, we should add MissileCallsOnDie = yes for SupW_AuroraFuelBombWeapon
// and change m_dieOnDetonate back to false.
wt->m_dieOnDetonate = TRUE;
DEBUG_LOG(("WeaponStore::newWeaponTemplate() - forcing MissileCallsOnDie for %s", name.str()));
}

m_weaponTemplateVector.push_back(wt);
m_weaponTemplateHashMap[wt->m_nameKey] = wt;

Expand Down