Skip to content

Commit fe49f3b

Browse files
authored
bugfix(tunnel): Fix stacked unit healing time inside multiple GLA Tunnel Networks (#1626)
To restore a quasi instant build like the retail game did with many tunnels, reduce the value of 'TimeForFullHeal' in TunnelContain modules Behavior = TunnelContain ModuleTag TimeForFullHeal = 5000 ; (in milliseconds) End
1 parent dbdcd89 commit fe49f3b

File tree

13 files changed

+145
-4
lines changed

13 files changed

+145
-4
lines changed

Generals/Code/GameEngine/Include/Common/TunnelTracker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ class TunnelTracker : public MemoryPoolObject,
6262
static void destroyObject( Object *obj, void *userData ); ///< Callback for Iterate Contained system
6363
static void healObject( Object *obj, void *frames ); ///< Callback for Iterate Contained system
6464

65+
#if RETAIL_COMPATIBLE_CRC
6566
void healObjects(Real frames); ///< heal all objects within the tunnel
67+
#else
68+
void healObjects(); ///< heal all objects within the tunnel
69+
#endif
6670

6771
UnsignedInt friend_getTunnelCount() const {return m_tunnelCount;}///< TunnelContains are allowed to ask if they are the last one ahead of deletion time
6872

@@ -78,12 +82,15 @@ class TunnelTracker : public MemoryPoolObject,
7882
virtual void loadPostProcess( void );
7983

8084
private:
85+
void updateFullHealTime();
8186

8287
std::list< ObjectID > m_tunnelIDs; ///< I have to try to keep track of these because Caves need to iterate on them.
8388
ContainedItemsList m_containList; ///< the contained object pointers list
8489
std::list< ObjectID > m_xferContainList;///< for loading of m_containList during post processing
8590
Int m_containListSize; ///< size of the contain list
8691
UnsignedInt m_tunnelCount; ///< How many tunnels have registered so we know when we should kill our contain list
92+
UnsignedInt m_framesForFullHeal; ///< How many frames it takes to fully heal a unit
93+
Bool m_needsFullHealTimeUpdate; ///< Set to true when needing to recalc full heal time to batch the operation
8794

8895
ObjectID m_curNemesisID; ///< If we have team(s) guarding a tunnel network system, this is one of the current targets.
8996
UnsignedInt m_nemesisTimestamp; ///< We only keep nemesis for a couple of seconds.

Generals/Code/GameEngine/Include/GameLogic/Module/ContainModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class ContainModuleInterface
8686
virtual Bool isGarrisonable() const = 0;
8787
virtual Bool isSpecialZeroSlotContainer() const = 0;
8888
virtual Bool isHealContain() const = 0;
89+
virtual Bool isTunnelContain() const = 0;
8990
virtual Bool isImmuneToClearBuildingAttacks() const = 0;
9091

9192

Generals/Code/GameEngine/Include/GameLogic/Module/HealContain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class HealContain : public OpenContain
6666

6767
virtual UpdateSleepTime update(); ///< called once per frame
6868
virtual Bool isHealContain() const { return true; } ///< true when container only contains units while healing (not a transport!)
69+
virtual Bool isTunnelContain() const { return FALSE; }
6970

7071
protected:
7172

Generals/Code/GameEngine/Include/GameLogic/Module/OpenContain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class OpenContain : public UpdateModule,
191191

192192
virtual Bool isGarrisonable() const { return false; } ///< can this unit be Garrisoned? (ick)
193193
virtual Bool isHealContain() const { return false; } ///< true when container only contains units while healing (not a transport!)
194+
virtual Bool isTunnelContain() const { return FALSE; }
194195
virtual Bool isSpecialZeroSlotContainer() const { return false; }
195196
virtual Bool isImmuneToClearBuildingAttacks() const { return true; }
196197

Generals/Code/GameEngine/Include/GameLogic/Module/TunnelContain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class TunnelContain : public OpenContain, public CreateModuleInterface
110110
virtual UnsignedInt getContainCount() const;
111111
virtual Int getContainMax( void ) const;
112112
virtual const ContainedItemsList* getContainedItemsList() const;
113+
virtual UnsignedInt getFullTimeForHeal(void) const; ///< Returns the time in frames until a contained object becomes fully healed
113114
virtual Bool isDisplayedOnControlBar() const { return TRUE; } ///< Does this container display its contents on the ControlBar?
114115
virtual Bool isKickOutOnCapture(){ return FALSE; }///< Caves and Tunnels don't kick out on capture.
115116

Generals/Code/GameEngine/Source/Common/RTS/Player.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,14 @@ void Player::update()
666666
team->updateGenericScripts();
667667
}
668668
}
669+
670+
#if !RETAIL_COMPATIBLE_CRC
671+
// TheSuperHackers @bugfix Stubbjax 26/09/2025 The Tunnel System now heals
672+
// all units once per frame instead of once per frame per Tunnel Network.
673+
TunnelTracker* tunnelSystem = getTunnelSystem();
674+
if (tunnelSystem)
675+
tunnelSystem->healObjects();
676+
#endif
669677
}
670678

671679
//=============================================================================

Generals/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ TunnelTracker::TunnelTracker()
5454
m_containListSize = 0;
5555
m_curNemesisID = INVALID_ID;
5656
m_nemesisTimestamp = 0;
57+
m_framesForFullHeal = 0;
58+
m_needsFullHealTimeUpdate = false;
5759
}
5860

5961
// ------------------------------------------------------------------------
@@ -211,13 +213,15 @@ void TunnelTracker::onTunnelCreated( const Object *newTunnel )
211213
{
212214
m_tunnelCount++;
213215
m_tunnelIDs.push_back( newTunnel->getID() );
216+
m_needsFullHealTimeUpdate = true;
214217
}
215218

216219
// ------------------------------------------------------------------------
217220
void TunnelTracker::onTunnelDestroyed( const Object *deadTunnel )
218221
{
219222
m_tunnelCount--;
220223
m_tunnelIDs.remove( deadTunnel->getID() );
224+
m_needsFullHealTimeUpdate = true;
221225

222226
if( m_tunnelCount == 0 )
223227
{
@@ -252,18 +256,35 @@ void TunnelTracker::destroyObject( Object *obj, void * )
252256

253257
// ------------------------------------------------------------------------
254258
// heal all the objects within the tunnel system using the iterateContained function
259+
#if RETAIL_COMPATIBLE_CRC
255260
void TunnelTracker::healObjects(Real frames)
256261
{
257262
iterateContained(healObject, &frames, FALSE);
258263
}
264+
#else
265+
void TunnelTracker::healObjects()
266+
{
267+
if (m_needsFullHealTimeUpdate)
268+
{
269+
updateFullHealTime();
270+
m_needsFullHealTimeUpdate = false;
271+
}
272+
273+
iterateContained(healObject, &m_framesForFullHeal, FALSE);
274+
}
275+
#endif
259276

260277
// ------------------------------------------------------------------------
261278
// heal one object within the tunnel network system
262279
void TunnelTracker::healObject( Object *obj, void *frames)
263280
{
264281

265282
//get the number of frames to heal
283+
#if RETAIL_COMPATIBLE_CRC
266284
Real *framesForFullHeal = (Real*)frames;
285+
#else
286+
UnsignedInt* framesForFullHeal = (UnsignedInt*)frames;
287+
#endif
267288

268289
// setup the healing damageInfo structure with all but the amount
269290
DamageInfo healInfo;
@@ -300,6 +321,31 @@ void TunnelTracker::healObject( Object *obj, void *frames)
300321
}
301322
}
302323

324+
void TunnelTracker::updateFullHealTime()
325+
{
326+
UnsignedInt minFrames = ~0u;
327+
328+
for (std::list<ObjectID>::const_iterator it = m_tunnelIDs.begin(); it != m_tunnelIDs.end(); ++it)
329+
{
330+
const Object* tunnelObj = TheGameLogic->findObjectByID(*it);
331+
if (!tunnelObj)
332+
continue;
333+
334+
const ContainModuleInterface* contain = tunnelObj->getContain();
335+
DEBUG_ASSERTCRASH(contain != NULL, ("Contain module is NULL"));
336+
337+
if (!contain->isTunnelContain())
338+
continue;
339+
340+
const TunnelContain* tunnelContain = static_cast<const TunnelContain*>(contain);
341+
const UnsignedInt framesForFullHeal = tunnelContain->getFullTimeForHeal();
342+
if (framesForFullHeal < minFrames)
343+
minFrames = framesForFullHeal;
344+
}
345+
346+
m_framesForFullHeal = minFrames;
347+
}
348+
303349
// ------------------------------------------------------------------------------------------------
304350
/** CRC */
305351
// ------------------------------------------------------------------------------------------------
@@ -353,6 +399,7 @@ void TunnelTracker::xfer( Xfer *xfer )
353399

354400
}
355401

402+
m_needsFullHealTimeUpdate = true;
356403
}
357404

358405
// tunnel count

Generals/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,11 @@ const ContainedItemsList* TunnelContain::getContainedItemsList() const
248248
return NULL;
249249
}
250250

251-
251+
UnsignedInt TunnelContain::getFullTimeForHeal(void) const
252+
{
253+
const TunnelContainModuleData* modData = getTunnelContainModuleData();
254+
return modData->m_framesForFullHeal;
255+
}
252256

253257
///////////////////////////////////////////////////////////////////////////////////////////////////
254258
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////
@@ -389,7 +393,6 @@ UpdateSleepTime TunnelContain::update( void )
389393
{
390394
// extending functionality to heal the units within the tunnel system
391395
OpenContain::update();
392-
const TunnelContainModuleData *modData = getTunnelContainModuleData();
393396

394397
Object *obj = getObject();
395398
Player *controllingPlayer = NULL;
@@ -400,10 +403,13 @@ UpdateSleepTime TunnelContain::update( void )
400403
if (controllingPlayer)
401404
{
402405
TunnelTracker *tunnelSystem = controllingPlayer->getTunnelSystem();
406+
#if RETAIL_COMPATIBLE_CRC
403407
if (tunnelSystem)
404408
{
409+
const TunnelContainModuleData* modData = getTunnelContainModuleData();
405410
tunnelSystem->healObjects(modData->m_framesForFullHeal);
406411
}
412+
#endif
407413

408414
// check for attacked.
409415
BodyModuleInterface *body = obj->getBodyModule();

GeneralsMD/Code/GameEngine/Include/Common/TunnelTracker.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ class TunnelTracker : public MemoryPoolObject,
6262
static void destroyObject( Object *obj, void *userData ); ///< Callback for Iterate Contained system
6363
static void healObject( Object *obj, void *frames ); ///< Callback for Iterate Contained system
6464

65+
#if RETAIL_COMPATIBLE_CRC
6566
void healObjects(Real frames); ///< heal all objects within the tunnel
67+
#else
68+
void healObjects(); ///< heal all objects within the tunnel
69+
#endif
6670

6771
UnsignedInt friend_getTunnelCount() const {return m_tunnelCount;}///< TunnelContains are allowed to ask if they are the last one ahead of deletion time
6872

@@ -78,12 +82,15 @@ class TunnelTracker : public MemoryPoolObject,
7882
virtual void loadPostProcess( void );
7983

8084
private:
85+
void updateFullHealTime();
8186

8287
std::list< ObjectID > m_tunnelIDs; ///< I have to try to keep track of these because Caves need to iterate on them.
8388
ContainedItemsList m_containList; ///< the contained object pointers list
8489
std::list< ObjectID > m_xferContainList;///< for loading of m_containList during post processing
8590
Int m_containListSize; ///< size of the contain list
8691
UnsignedInt m_tunnelCount; ///< How many tunnels have registered so we know when we should kill our contain list
92+
UnsignedInt m_framesForFullHeal; ///< How many frames it takes to fully heal a unit
93+
Bool m_needsFullHealTimeUpdate; ///< Set to true when needing to recalc full heal time to batch the operation
8794

8895
ObjectID m_curNemesisID; ///< If we have team(s) guarding a tunnel network system, this is one of the current targets.
8996
UnsignedInt m_nemesisTimestamp; ///< We only keep nemesis for a couple of seconds.

GeneralsMD/Code/GameEngine/Include/GameLogic/Module/TunnelContain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class TunnelContain : public OpenContain, public CreateModuleInterface
117117
virtual UnsignedInt getContainCount() const;
118118
virtual Int getContainMax( void ) const;
119119
virtual const ContainedItemsList* getContainedItemsList() const;
120+
virtual UnsignedInt getFullTimeForHeal(void) const; ///< Returns the time in frames until a contained object becomes fully healed
120121
virtual Bool isDisplayedOnControlBar() const { return TRUE; } ///< Does this container display its contents on the ControlBar?
121122
virtual Bool isKickOutOnCapture(){ return FALSE; }///< Caves and Tunnels don't kick out on capture.
122123

0 commit comments

Comments
 (0)