diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt
index 6e253d30de..135c9bbda2 100644
--- a/GeneralsMD/Code/GameEngine/CMakeLists.txt
+++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt
@@ -1,16 +1,16 @@
set(GAMEENGINE_SRC
Include/Common/AcademyStats.h
Include/Common/ActionManager.h
-# Include/Common/ArchiveFile.h
-# Include/Common/ArchiveFileSystem.h
-# Include/Common/AsciiString.h
-# Include/Common/AudioAffect.h
-# Include/Common/AudioEventInfo.h
-# Include/Common/AudioEventRTS.h
-# Include/Common/AudioHandleSpecialValues.h
-# Include/Common/AudioRandomValue.h
-# Include/Common/AudioRequest.h
-# Include/Common/AudioSettings.h
+# Include/Common/ArchiveFile.h
+# Include/Common/ArchiveFileSystem.h
+# Include/Common/AsciiString.h
+# Include/Common/AudioAffect.h
+# Include/Common/AudioEventInfo.h
+# Include/Common/AudioEventRTS.h
+# Include/Common/AudioHandleSpecialValues.h
+# Include/Common/AudioRandomValue.h
+# Include/Common/AudioRequest.h
+# Include/Common/AudioSettings.h
Include/Common/BattleHonors.h
Include/Common/BezFwdIterator.h
Include/Common/BezierSegment.h
@@ -33,21 +33,21 @@ set(GAMEENGINE_SRC
Include/Common/DisabledTypes.h
Include/Common/DiscreteCircle.h
Include/Common/DrawModule.h
-# Include/Common/DynamicAudioEventInfo.h
+# Include/Common/DynamicAudioEventInfo.h
Include/Common/encrypt.h
Include/Common/Energy.h
Include/Common/Errors.h
-# Include/Common/file.h
-# Include/Common/FileSystem.h
+# Include/Common/file.h
+# Include/Common/FileSystem.h
Include/Common/FunctionLexicon.h
-# Include/Common/GameAudio.h
+# Include/Common/GameAudio.h
Include/Common/GameCommon.h
-# Include/Common/GameDefines.h
+# Include/Common/GameDefines.h
Include/Common/GameEngine.h
Include/Common/GameLOD.h
Include/Common/GameMemory.h
-# Include/Common/GameMusic.h
-# Include/Common/GameSounds.h
+# Include/Common/GameMusic.h
+# Include/Common/GameSounds.h
Include/Common/GameSpyMiscPreferences.h
Include/Common/GameState.h
Include/Common/GameStateMap.h
@@ -63,13 +63,13 @@ set(GAMEENGINE_SRC
Include/Common/Language.h
Include/Common/LatchRestore.h
Include/Common/List.h
-# Include/Common/LocalFile.h
-# Include/Common/LocalFileSystem.h
+# Include/Common/LocalFile.h
+# Include/Common/LocalFileSystem.h
Include/Common/MapObject.h
Include/Common/MapReaderWriterInfo.h
Include/Common/MessageStream.h
Include/Common/MiniLog.h
-# Include/Common/MiscAudio.h
+# Include/Common/MiscAudio.h
Include/Common/MissionStats.h
Include/Common/ModelState.h
Include/Common/Module.h
@@ -91,16 +91,16 @@ set(GAMEENGINE_SRC
Include/Common/QuickmatchPreferences.h
Include/Common/QuotedPrintable.h
Include/Common/Radar.h
-# Include/Common/RAMFile.h
+# Include/Common/RAMFile.h
Include/Common/RandomValue.h
Include/Common/Recorder.h
-# Include/Common/ReplaySimulation.h
+# Include/Common/ReplaySimulation.h
Include/Common/Registry.h
Include/Common/ResourceGatheringManager.h
Include/Common/Science.h
Include/Common/ScopedMutex.h
Include/Common/ScoreKeeper.h
-# Include/Common/simpleplayer.h
+# Include/Common/simpleplayer.h
Include/Common/SkirmishBattleHonors.h
Include/Common/SkirmishPreferences.h
Include/Common/Snapshot.h
@@ -112,7 +112,7 @@ set(GAMEENGINE_SRC
Include/Common/StateMachine.h
Include/Common/StatsCollector.h
Include/Common/STLTypedefs.h
-# Include/Common/StreamingArchiveFile.h
+# Include/Common/StreamingArchiveFile.h
Include/Common/SubsystemInterface.h
Include/Common/SystemInfo.h
Include/Common/Team.h
@@ -123,14 +123,14 @@ set(GAMEENGINE_SRC
Include/Common/ThingSort.h
Include/Common/ThingTemplate.h
Include/Common/TunnelTracker.h
-# Include/Common/UnicodeString.h
+# Include/Common/UnicodeString.h
Include/Common/UnitTimings.h
Include/Common/Upgrade.h
-# Include/Common/urllaunch.h
+# Include/Common/urllaunch.h
Include/Common/UserPreferences.h
Include/Common/version.h
Include/Common/WellKnownKeys.h
-# Include/Common/WorkerProcess.h
+# Include/Common/WorkerProcess.h
# Include/Common/Xfer.h
# Include/Common/XferCRC.h
# Include/Common/XferDeepCRC.h
@@ -205,6 +205,7 @@ set(GAMEENGINE_SRC
Include/GameClient/Module/AnimatedParticleSysBoneClientUpdate.h
Include/GameClient/Module/BeaconClientUpdate.h
Include/GameClient/Module/SwayClientUpdate.h
+ Include/GameClient/Module/DynamicGeometryClientUpdate.h
Include/GameClient/Mouse.h
Include/GameClient/ParabolicEase.h
Include/GameClient/ParticleSys.h
@@ -563,14 +564,14 @@ set(GAMEENGINE_SRC
Include/GameNetwork/WOLBrowser/FEBDispatch.h
Include/GameNetwork/WOLBrowser/WebBrowser.h
Include/Precompiled/PreRTS.h
-# Source/Common/Audio/AudioEventRTS.cpp
-# Source/Common/Audio/AudioRequest.cpp
-# Source/Common/Audio/DynamicAudioEventInfo.cpp
-# Source/Common/Audio/GameAudio.cpp
-# Source/Common/Audio/GameMusic.cpp
-# Source/Common/Audio/GameSounds.cpp
- #Source/Common/Audio/simpleplayer.cpp # unused
- #Source/Common/Audio/urllaunch.cpp # unused
+# Source/Common/Audio/AudioEventRTS.cpp
+# Source/Common/Audio/AudioRequest.cpp
+# Source/Common/Audio/DynamicAudioEventInfo.cpp
+# Source/Common/Audio/GameAudio.cpp
+# Source/Common/Audio/GameMusic.cpp
+# Source/Common/Audio/GameSounds.cpp
+ #Source/Common/Audio/simpleplayer.cpp # unused
+ #Source/Common/Audio/urllaunch.cpp # unused
Source/Common/Bezier/BezFwdIterator.cpp
Source/Common/Bezier/BezierSegment.cpp
Source/Common/BitFlags.cpp
@@ -587,7 +588,7 @@ set(GAMEENGINE_SRC
Source/Common/INI/INI.cpp
Source/Common/INI/INIAiData.cpp
Source/Common/INI/INIAnimation.cpp
-# Source/Common/INI/INIAudioEventInfo.cpp
+# Source/Common/INI/INIAudioEventInfo.cpp
Source/Common/INI/INICommandButton.cpp
Source/Common/INI/INICommandSet.cpp
Source/Common/INI/INIControlBarScheme.cpp
@@ -598,7 +599,7 @@ set(GAMEENGINE_SRC
Source/Common/INI/INIMapCache.cpp
Source/Common/INI/INIMapData.cpp
Source/Common/INI/INIMappedImage.cpp
-# Source/Common/INI/INIMiscAudio.cpp
+# Source/Common/INI/INIMiscAudio.cpp
Source/Common/INI/INIModel.cpp
Source/Common/INI/INIMultiplayer.cpp
Source/Common/INI/INIObject.cpp
@@ -621,7 +622,7 @@ set(GAMEENGINE_SRC
Source/Common/PerfTimer.cpp
Source/Common/RandomValue.cpp
Source/Common/Recorder.cpp
-# Source/Common/ReplaySimulation.cpp
+# Source/Common/ReplaySimulation.cpp
Source/Common/RTS/AcademyStats.cpp
Source/Common/RTS/ActionManager.cpp
Source/Common/RTS/Energy.cpp
@@ -641,9 +642,9 @@ set(GAMEENGINE_SRC
Source/Common/SkirmishBattleHonors.cpp
Source/Common/StateMachine.cpp
Source/Common/StatsCollector.cpp
-# Source/Common/System/ArchiveFile.cpp
-# Source/Common/System/ArchiveFileSystem.cpp
-# Source/Common/System/AsciiString.cpp
+# Source/Common/System/ArchiveFile.cpp
+# Source/Common/System/ArchiveFileSystem.cpp
+# Source/Common/System/AsciiString.cpp
Source/Common/System/BuildAssistant.cpp
Source/Common/System/CDManager.cpp
Source/Common/System/CriticalSection.cpp
@@ -652,8 +653,8 @@ set(GAMEENGINE_SRC
Source/Common/System/Directory.cpp
Source/Common/System/DisabledTypes.cpp
Source/Common/System/encrypt.cpp
-# Source/Common/System/File.cpp
-# Source/Common/System/FileSystem.cpp
+# Source/Common/System/File.cpp
+# Source/Common/System/FileSystem.cpp
Source/Common/System/FunctionLexicon.cpp
Source/Common/System/GameCommon.cpp
#Source/Common/System/GameMemory.cpp
@@ -661,22 +662,22 @@ set(GAMEENGINE_SRC
Source/Common/System/Geometry.cpp
Source/Common/System/KindOf.cpp
Source/Common/System/List.cpp
-# Source/Common/System/LocalFile.cpp
-# Source/Common/System/LocalFileSystem.cpp
+# Source/Common/System/LocalFile.cpp
+# Source/Common/System/LocalFileSystem.cpp
#Source/Common/System/MemoryInit.cpp
Source/Common/System/ObjectStatusTypes.cpp
Source/Common/System/QuotedPrintable.cpp
Source/Common/System/Radar.cpp
-# Source/Common/System/RAMFile.cpp
+# Source/Common/System/RAMFile.cpp
Source/Common/System/registry.cpp
Source/Common/System/SaveGame/GameState.cpp
Source/Common/System/SaveGame/GameStateMap.cpp
Source/Common/System/Snapshot.cpp
Source/Common/System/StackDump.cpp
-# Source/Common/System/StreamingArchiveFile.cpp
+# Source/Common/System/StreamingArchiveFile.cpp
Source/Common/System/SubsystemInterface.cpp
Source/Common/System/Trig.cpp
-# Source/Common/System/UnicodeString.cpp
+# Source/Common/System/UnicodeString.cpp
Source/Common/System/Upgrade.cpp
# Source/Common/System/Xfer.cpp
# Source/Common/System/XferCRC.cpp
@@ -691,7 +692,7 @@ set(GAMEENGINE_SRC
Source/Common/Thing/ThingTemplate.cpp
Source/Common/UserPreferences.cpp
Source/Common/version.cpp
-# Source/Common/WorkerProcess.cpp
+# Source/Common/WorkerProcess.cpp
Source/GameClient/ClientInstance.cpp
Source/GameClient/Color.cpp
Source/GameClient/Credits.cpp
@@ -702,6 +703,7 @@ set(GAMEENGINE_SRC
Source/GameClient/Drawable/Update/AnimatedParticleSysBoneClientUpdate.cpp
Source/GameClient/Drawable/Update/BeaconClientUpdate.cpp
Source/GameClient/Drawable/Update/SwayClientUpdate.cpp
+ Source/GameClient/Drawable/Update/DynamicGeometryClientUpdate.cpp
Source/GameClient/DrawGroupInfo.cpp
Source/GameClient/Eva.cpp
Source/GameClient/FXList.cpp
@@ -826,7 +828,7 @@ set(GAMEENGINE_SRC
Source/GameClient/Statistics.cpp
Source/GameClient/System/Anim2D.cpp
Source/GameClient/System/CampaignManager.cpp
-# "Source/GameClient/System/Debug Displayers/AudioDebugDisplay.cpp"
+# "Source/GameClient/System/Debug Displayers/AudioDebugDisplay.cpp"
Source/GameClient/System/DebugDisplay.cpp
Source/GameClient/System/Image.cpp
Source/GameClient/System/ParticleSys.cpp
diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Module/DynamicGeometryClientUpdate.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Module/DynamicGeometryClientUpdate.h
new file mode 100644
index 0000000000..097430ff85
--- /dev/null
+++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Module/DynamicGeometryClientUpdate.h
@@ -0,0 +1,89 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2025 Electronic Arts Inc.
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// //
+// (c) 2001-2003 Electronic Arts Inc. //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+// FILE: DynamicGeometryClientUpdate.h ////////////////////////////////////////////////////////////////////
+// Author: Andi W, August 2025
+// Desc: Simple Alpha/Scale transition
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#ifndef __DynamicGeometryClientUpdate_H_
+#define __DynamicGeometryClientUpdate_H_
+
+// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
+#include "Common/ClientUpdateModule.h"
+
+// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
+
+//-------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------
+class DynamicGeometryClientUpdateModuleData : public ClientUpdateModuleData
+{
+public:
+ Real m_scaleInitial;
+ Real m_scaleMidpoint;
+ Real m_scaleFinal;
+
+ Real m_alphaInitial;
+ Real m_alphaMidpoint;
+ Real m_alphaFinal;
+
+ UnsignedInt m_totalFrames;
+ UnsignedInt m_midpointFrames;
+
+ UnsignedInt m_interpolationType;
+
+ DynamicGeometryClientUpdateModuleData();
+ ~DynamicGeometryClientUpdateModuleData();
+ static void buildFieldParse(MultiIniFieldParse& p);
+};
+//-------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------
+class DynamicGeometryClientUpdate : public ClientUpdateModule
+{
+
+ MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( DynamicGeometryClientUpdate, "DynamicGeometryClientUpdate" )
+ MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( DynamicGeometryClientUpdate, DynamicGeometryClientUpdateModuleData);
+
+public:
+
+ DynamicGeometryClientUpdate( Thing *thing, const ModuleData* moduleData );
+ // virtual destructor prototype provided by memory pool declaration
+
+ /// the client update callback
+ virtual void clientUpdate( void );
+
+ void setScaleMultiplier( Real value ) { m_overrideScale = value; }
+ void setAlphaMultiplier( Real value ) { m_overrideAlpha = value; }
+
+protected:
+
+ UnsignedInt m_startFrame;
+ Real m_overrideScale;
+ Real m_overrideAlpha;
+};
+
+#endif // __DynamicGeometryClientUpdate_H_
+
diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ChronoDeathBehavior.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ChronoDeathBehavior.h
index 45a0af952c..9ffdeae9e6 100644
--- a/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ChronoDeathBehavior.h
+++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/Module/ChronoDeathBehavior.h
@@ -54,6 +54,8 @@ class ChronoDeathBehaviorModuleData : public UpdateModuleData
Real m_startAlpha;
Real m_endAlpha;
+ Real m_oclScaleFactor;
+
UnsignedInt m_destructionDelay;
ChronoDeathBehaviorModuleData();
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp
index 7e7ddf5326..a4387c1a60 100644
--- a/GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/Common/System/MemoryInit.cpp
@@ -119,6 +119,7 @@ static PoolSizeRec sizes[] =
{ "WindowLayoutPool", 32, 32 },
{ "AnimatedParticleSysBoneClientUpdate", 16, 16 },
{ "SwayClientUpdate", 32, 32 },
+ { "DynamicGeometryClientUpdate", 32, 32 },
{ "BeaconClientUpdate", 64, 32 },
{ "AIGroupPool", 64, 32 },
{ "AIDockMachinePool", 256, 32 },
diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp
index 77ef69782a..5b3850300d 100644
--- a/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp
@@ -289,6 +289,7 @@
// client update includes
#include "GameClient/Module/AnimatedParticleSysBoneClientUpdate.h"
#include "GameClient/Module/SwayClientUpdate.h"
+#include "GameClient/Module/DynamicGeometryClientUpdate.h"
#include "GameClient/Module/BeaconClientUpdate.h"
// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
@@ -577,6 +578,7 @@ void ModuleFactory::init( void )
// client update modules
addModule( AnimatedParticleSysBoneClientUpdate );
addModule( SwayClientUpdate );
+ addModule( DynamicGeometryClientUpdate );
addModule( BeaconClientUpdate );
} // end init
diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable/Update/DynamicGeometryClientUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable/Update/DynamicGeometryClientUpdate.cpp
new file mode 100644
index 0000000000..6d062cc346
--- /dev/null
+++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable/Update/DynamicGeometryClientUpdate.cpp
@@ -0,0 +1,251 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2025 Electronic Arts Inc.
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+////////////////////////////////////////////////////////////////////////////////
+// //
+// (c) 2001-2003 Electronic Arts Inc. //
+// //
+////////////////////////////////////////////////////////////////////////////////
+
+// FILE: DynamicGeometryClientUpdate.cpp //////////////////////////////////////////////////////////////////
+// Author: Andi W, August 2025
+// Desc: Simple Alpha/Scale transition
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
+#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
+
+#include "GameClient/Drawable.h"
+#include "GameClient/Module/DynamicGeometryClientUpdate.h"
+#include "Common/Xfer.h"
+#include "GameLogic/GameLogic.h"
+
+
+//-------------------------------------------------------------------------------------------------
+DynamicGeometryClientUpdateModuleData::DynamicGeometryClientUpdateModuleData()
+{
+ m_scaleInitial = 1.0;
+ m_scaleMidpoint = 1.0;
+ m_scaleFinal = 1.0;
+
+ m_alphaInitial = 1.0;
+ m_alphaMidpoint = 1.0;
+ m_alphaFinal = 1.0;
+
+ m_totalFrames = 30;
+ m_midpointFrames = 15;
+}
+
+//-------------------------------------------------------------------------------------------------
+DynamicGeometryClientUpdateModuleData::~DynamicGeometryClientUpdateModuleData()
+{
+}
+
+//-------------------------------------------------------------------------------------------------
+enum DynamicGeometryPhaseType CPP_11(: Int)
+{
+ DGPHASE_INITIAL = 0,
+ DGPHASE_MIDPOINT,
+ DGPHASE_FINAL
+};
+
+static const char* TheDynamicGeometryPhaseNames[] =
+{
+ "INITIAL",
+ "MIDPOINT",
+ "FINAL"
+};
+// -----------------------------------------------------------------------------------------------
+enum DynamicGeometryInterpolationType CPP_11(: Int)
+{
+ DGINTERP_LINEAR = 0,
+ DGINTERP_SMOOTH
+};
+
+static const char* TheInterpolationTypeNames[] =
+{
+ "LINEAR",
+ "SMOOTH"
+};
+
+//-------------------------------------------------------------------------------------------------
+static void parseAlpha(INI* ini, void* instance, void* /*store*/, const void* /*userData*/)
+{
+ DynamicGeometryClientUpdateModuleData* self = (DynamicGeometryClientUpdateModuleData*)instance;
+ DynamicGeometryPhaseType phase = (DynamicGeometryPhaseType)INI::scanIndexList(ini->getNextToken(), TheDynamicGeometryPhaseNames);
+
+ const char* token = ini->getNextToken();
+ Real value = INI::scanReal(token);
+
+ if (phase == DGPHASE_INITIAL)
+ self->m_alphaInitial = value;
+ else if (phase == DGPHASE_MIDPOINT)
+ self->m_alphaMidpoint = value;
+ else if (phase == DGPHASE_FINAL)
+ self->m_alphaFinal = value;
+}
+
+//-------------------------------------------------------------------------------------------------
+static void parseScale(INI* ini, void* instance, void* /*store*/, const void* /*userData*/)
+{
+ DynamicGeometryClientUpdateModuleData* self = (DynamicGeometryClientUpdateModuleData*)instance;
+ DynamicGeometryPhaseType phase = (DynamicGeometryPhaseType)INI::scanIndexList(ini->getNextToken(), TheDynamicGeometryPhaseNames);
+
+ const char* token = ini->getNextToken();
+ Real value = INI::scanReal(token);
+
+ if (phase == DGPHASE_INITIAL)
+ self->m_scaleInitial = value;
+ else if (phase == DGPHASE_MIDPOINT)
+ self->m_scaleMidpoint = value;
+ else if (phase == DGPHASE_FINAL)
+ self->m_scaleFinal = value;
+}
+
+//-------------------------------------------------------------------------------------------------
+void DynamicGeometryClientUpdateModuleData::buildFieldParse(MultiIniFieldParse& p)
+{
+ ClientUpdateModuleData::buildFieldParse(p);
+
+ static const FieldParse dataFieldParse[] =
+ {
+ { "Opacity", parseAlpha, NULL, NULL},
+ { "Scale", parseScale, NULL, NULL},
+ { "Interpolation", INI::parseIndexList, TheInterpolationTypeNames, offsetof(DynamicGeometryClientUpdateModuleData, m_interpolationType)},
+ { "TotalDuration", INI::parseDurationUnsignedInt, NULL, offsetof(DynamicGeometryClientUpdateModuleData, m_totalFrames) },
+ { "MidpointDuration", INI::parseDurationUnsignedInt, NULL, offsetof(DynamicGeometryClientUpdateModuleData, m_midpointFrames) },
+ { 0, 0, 0, 0 }
+ };
+ p.add(dataFieldParse);
+}
+
+//-------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------
+DynamicGeometryClientUpdate::DynamicGeometryClientUpdate( Thing *thing, const ModuleData* moduleData ) :
+ ClientUpdateModule( thing, moduleData )
+{
+ m_startFrame = TheGameLogic->getFrame();
+ m_overrideScale = 1.0;
+ m_overrideAlpha = 1.0;
+}
+
+//-------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------
+DynamicGeometryClientUpdate::~DynamicGeometryClientUpdate( void )
+{
+
+}
+//-------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------------------------------
+/** The client update callback. */
+//-------------------------------------------------------------------------------------------------
+void DynamicGeometryClientUpdate::clientUpdate( void )
+{
+ Drawable *draw = getDrawable();
+
+ if (!draw)
+ return;
+
+ const DynamicGeometryClientUpdateModuleData* data = getDynamicGeometryClientUpdateModuleData();
+
+ UnsignedInt now = TheGameLogic->getFrame();
+
+ Real alpha0, alpha1, scale0, scale1, progress;
+ if (now < m_startFrame + data->m_midpointFrames) {
+ alpha0 = data->m_alphaInitial;
+ alpha1 = data->m_alphaMidpoint;
+ scale0 = data->m_scaleInitial;
+ scale1 = data->m_scaleMidpoint;
+ progress = INT_TO_REAL(now - m_startFrame) / INT_TO_REAL(data->m_midpointFrames);
+ }
+ else if (now < m_startFrame + data->m_totalFrames) {
+ alpha0 = data->m_alphaMidpoint;
+ alpha1 = data->m_alphaFinal;
+ scale0 = data->m_scaleMidpoint;
+ scale1 = data->m_scaleFinal;
+ progress = INT_TO_REAL(now - (m_startFrame + data->m_midpointFrames)) / INT_TO_REAL(data->m_totalFrames - data->m_midpointFrames);
+ }
+ else {
+ // We are done
+ return;
+ }
+
+ if (data->m_interpolationType == DGINTERP_SMOOTH) {
+ progress = 0.5 - (Cos(progress * PI) * 0.5);
+ }
+
+ // DEBUG_LOG((">>> DGCU - progress = %f", progress));
+
+ Real alpha = (1.0 - progress) * alpha0 + progress * alpha1;
+ Real scale = (1.0 - progress) * scale0 + progress * scale1;
+
+ draw->setInstanceScale(m_overrideScale * scale);
+ draw->setDrawableOpacity(m_overrideAlpha * alpha);
+}
+
+// ------------------------------------------------------------------------------------------------
+/** CRC */
+// ------------------------------------------------------------------------------------------------
+void DynamicGeometryClientUpdate::crc( Xfer *xfer )
+{
+
+ // extend base class
+ ClientUpdateModule::crc( xfer );
+
+} // end crc
+
+// ------------------------------------------------------------------------------------------------
+/** Xfer method
+ * Version Info:
+ * 1: Initial version */
+// ------------------------------------------------------------------------------------------------
+void DynamicGeometryClientUpdate::xfer( Xfer *xfer )
+{
+
+ // version
+ XferVersion currentVersion = 1;
+ XferVersion version = currentVersion;
+ xfer->xferVersion( &version, currentVersion );
+
+ // extend base class
+ ClientUpdateModule::xfer( xfer );
+
+ // start frame
+ xfer->xferUnsignedInt(&m_startFrame);
+
+ // override scale value
+ xfer->xferReal(&m_overrideScale);
+
+ // override alpha value
+ xfer->xferReal(&m_overrideAlpha);
+
+} // end xfer
+
+// ------------------------------------------------------------------------------------------------
+/** Load post process */
+// ------------------------------------------------------------------------------------------------
+void DynamicGeometryClientUpdate::loadPostProcess( void )
+{
+
+ // extend base class
+ ClientUpdateModule::loadPostProcess();
+
+
+} // end loadPostProcess
diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/ChronoDeathBehavior.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/ChronoDeathBehavior.cpp
index c823ae6044..e21025c53d 100644
--- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/ChronoDeathBehavior.cpp
+++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Behavior/ChronoDeathBehavior.cpp
@@ -46,6 +46,7 @@
#include "GameLogic/Object.h"
#include "GameLogic/ObjectCreationList.h"
#include "GameClient/Drawable.h"
+#include "GameClient/Module/DynamicGeometryClientUpdate.h"
//-------------------------------------------------------------------------------------------------
ChronoDeathBehaviorModuleData::ChronoDeathBehaviorModuleData()
@@ -58,6 +59,7 @@ ChronoDeathBehaviorModuleData::ChronoDeathBehaviorModuleData()
m_startAlpha = 1.0;
m_endAlpha = 1.0;
m_destructionDelay = 1;
+ m_oclScaleFactor = 1.0;
}
//-------------------------------------------------------------------------------------------------
@@ -70,6 +72,7 @@ ChronoDeathBehaviorModuleData::ChronoDeathBehaviorModuleData()
{ "StartFX", INI::parseFXList, NULL, offsetof(ChronoDeathBehaviorModuleData, m_startFX) },
{ "EndFX", INI::parseFXList, NULL, offsetof(ChronoDeathBehaviorModuleData, m_endFX) },
{ "OCL", INI::parseObjectCreationList, NULL, offsetof(ChronoDeathBehaviorModuleData, m_ocl) },
+ { "OCLDynamicGeometryScaleFactor", INI::parseReal, NULL, offsetof(ChronoDeathBehaviorModuleData, m_oclScaleFactor) },
{ "StartScale", INI::parseReal, NULL, offsetof(ChronoDeathBehaviorModuleData, m_startScale) },
{ "EndScale", INI::parseReal, NULL, offsetof(ChronoDeathBehaviorModuleData, m_endScale) },
{ "StartOpacity", INI::parsePercentToReal, NULL, offsetof(ChronoDeathBehaviorModuleData, m_startAlpha) },
@@ -160,8 +163,23 @@ void ChronoDeathBehavior::beginChronoDeath(const DamageInfo* damageInfo)
if (d->m_ocl)
{
- // TODO: Create Dynamic Scale module and pass geometry size of parent object;
- /* Object* newObject = */ ObjectCreationList::create(d->m_ocl, obj, NULL);
+ // pass geometry size of parent object;
+ Object* newObject = ObjectCreationList::create(d->m_ocl, obj, NULL);
+ if (newObject != NULL && d->m_oclScaleFactor != 0.0) {
+ Drawable* oclDraw = newObject->getDrawable();
+ if (oclDraw != NULL) {
+ static NameKeyType key_dynamicGeometryUpdate = NAMEKEY("DynamicGeometryClientUpdate");
+ DynamicGeometryClientUpdate* update = (DynamicGeometryClientUpdate*)oclDraw->findClientUpdateModule(key_dynamicGeometryUpdate);
+ if (update) {
+ Real objRadius = getObject()->getGeometryInfo().getBoundingCircleRadius();
+
+ // DEBUG_LOG((">>> CDB - objRadius = %f", objRadius));
+
+ objRadius = MAX(10.0, MIN(objRadius, 100.0));
+ update->setScaleMultiplier(objRadius / d->m_oclScaleFactor);
+ }
+ }
+ }
}
UnsignedInt now = TheGameLogic->getFrame();