Skip to content

Commit fa500cc

Browse files
committed
2 parents be426a0 + 3dff319 commit fa500cc

File tree

8 files changed

+719
-4
lines changed

8 files changed

+719
-4
lines changed

Core/GameEngine/Source/Common/System/GameMemoryInitPools_GeneralsMD.inl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ static PoolSizeRec PoolSizes[] =
274274
{ "SupplyWarehouseCreate", 48, 16 },
275275
{ "SupplyWarehouseDockUpdate", 48, 16 },
276276
{ "EnemyNearUpdate", 1024, 32 },
277+
{ "ProximityCaptureUpdate", 32, 32 },
277278
{ "TechBuildingBehavior", 32, 32 },
278279
{ "ToppleUpdate", 256, 128 },
279280
{ "TransitionDamageFX", 384, 128 },

GeneralsMD/Code/GameEngine/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ set(GAMEENGINE_SRC
323323
Include/GameLogic/Module/EjectPilotDie.h
324324
Include/GameLogic/Module/EMPUpdate.h
325325
Include/GameLogic/Module/EnemyNearUpdate.h
326+
Include/GameLogic/Module/ProximityCaptureUpdate.h
326327
Include/GameLogic/Module/ExperienceScalarUpgrade.h
327328
Include/GameLogic/Module/FireOCLAfterWeaponCooldownUpdate.h
328329
Include/GameLogic/Module/FireSpreadUpdate.h
@@ -1062,6 +1063,7 @@ set(GAMEENGINE_SRC
10621063
Source/GameLogic/Object/Update/DynamicShroudClearingRangeUpdate.cpp
10631064
Source/GameLogic/Object/Update/EMPUpdate.cpp
10641065
Source/GameLogic/Object/Update/EnemyNearUpdate.cpp
1066+
Source/GameLogic/Object/Update/ProximityCaptureUpdate.cpp
10651067
Source/GameLogic/Object/Update/FireOCLAfterWeaponCooldownUpdate.cpp
10661068
Source/GameLogic/Object/Update/FireSpreadUpdate.cpp
10671069
Source/GameLogic/Object/Update/FirestormDynamicGeometryInfoUpdate.cpp
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 Electronic Arts Inc.
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
////////////////////////////////////////////////////////////////////////////////
20+
// //
21+
// (c) 2001-2003 Electronic Arts Inc. //
22+
// //
23+
////////////////////////////////////////////////////////////////////////////////
24+
25+
// FILE: ProximityCaptureUpdate.h /////////////////////////////////////////////////////////////////////////////
26+
// Author: Matthew D. Campbell, April 2002
27+
// Desc: Reacts when an enemy is within range
28+
///////////////////////////////////////////////////////////////////////////////////////////////////
29+
30+
#pragma once
31+
32+
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
33+
#include "GameLogic/Module/UpdateModule.h"
34+
#include "Common/KindOf.h"
35+
36+
// FORWARD REFERENCES /////////////////////////////////////////////////////////////////////////////
37+
class Object;
38+
// class AudioEventRTS;
39+
class FXList;
40+
41+
//-------------------------------------------------------------------------------------------------
42+
// ------------------------------------------------------------------------------------------------
43+
class ProximityCaptureUpdateModuleData : public UpdateModuleData
44+
{
45+
public:
46+
UnsignedInt m_captureTickDelay; ///< Time delay between evaluation ticks
47+
Real m_captureRate; ///< How much to capture per tick
48+
Real m_uncapRate; ///< How much progress to remove
49+
Real m_uncapRateNeutral; ///< How much progress to remove when neutral;
50+
Real m_recoverRate; ///< How much progress to recover when no units are around;
51+
Real m_captureRadius;
52+
KindOfMaskType m_requiredKindOf; ///< Must be set on target
53+
KindOfMaskType m_forbiddenKindOf; ///< Must be clear on target
54+
Bool m_isCountAirborne; ///< Affect Airborne targets
55+
Bool m_requiresAllKindOfs; ///< requires ALL requiredKindOfs or just one of them
56+
57+
Real m_unitValueContentionDelta; ///< unit values between players need to differ by this much to trigger capture
58+
Real m_unitValueCountFactor; ///< value factor for the number of units (i.e. equal value for each unit)
59+
//Real m_unitValueBuildCostFactor; ///< value factor for sellValue of the unit
60+
61+
Bool m_showProgressBar;
62+
63+
UnsignedShort m_capturePingInterval; ///< number of ticks between capture FX
64+
Bool m_showCapturePingFlash;
65+
Bool m_playDefectorPingSound;
66+
// AudioEventRTS m_capturePingSound;
67+
68+
const FXList* m_startCaptureFX;
69+
const FXList* m_startUncapFX;
70+
const FXList* m_finishCaptureFX;
71+
const FXList* m_capturePingFX;
72+
const FXList* m_capturePingContestedFX;
73+
74+
Int m_skillPointsForCapture; ///< grant XP to the player on capture
75+
76+
ProximityCaptureUpdateModuleData()
77+
{
78+
m_captureTickDelay = LOGICFRAMES_PER_SECOND;
79+
m_captureRate = 1.0 / 30.0f;
80+
m_uncapRate = 1.0 / 30.0f;
81+
m_uncapRateNeutral = -1.0f;
82+
m_recoverRate = -1.0f;
83+
84+
m_unitValueContentionDelta = 0.01;
85+
m_unitValueCountFactor = 1.0;
86+
//m_unitValueBuildCostFactor = 0.0;
87+
88+
m_startCaptureFX = NULL;
89+
m_startUncapFX = NULL;
90+
m_finishCaptureFX = NULL;
91+
m_capturePingFX = NULL;
92+
m_capturePingContestedFX = NULL;
93+
m_showCapturePingFlash = true;
94+
m_playDefectorPingSound = true;
95+
}
96+
97+
static void buildFieldParse(MultiIniFieldParse& p)
98+
{
99+
UpdateModuleData::buildFieldParse(p);
100+
static const FieldParse dataFieldParse[] =
101+
{
102+
{ "CaptureTickDelay", INI::parseDurationUnsignedInt, NULL, offsetof( ProximityCaptureUpdateModuleData, m_captureTickDelay) },
103+
{ "CaptureRadius", INI::parseReal, NULL, offsetof( ProximityCaptureUpdateModuleData, m_captureRadius) },
104+
{ "CaptureProgressPerTick", INI::parsePercentToReal, NULL, offsetof( ProximityCaptureUpdateModuleData, m_captureRate) },
105+
{ "CaptureProgressRemovePerTick", INI::parsePercentToReal, NULL, offsetof( ProximityCaptureUpdateModuleData, m_uncapRate) },
106+
{ "CaptureProgressRemovePerTickFromNeutral", INI::parsePercentToReal, NULL, offsetof( ProximityCaptureUpdateModuleData, m_uncapRateNeutral) },
107+
{ "CaptureProgressRecoverPerTick", INI::parsePercentToReal, NULL, offsetof( ProximityCaptureUpdateModuleData, m_recoverRate) },
108+
{ "RequiredKindOf", KindOfMaskType::parseFromINI, NULL, offsetof(ProximityCaptureUpdateModuleData, m_requiredKindOf) },
109+
{ "RequiresAllKindOfs", INI::parseBool, NULL, offsetof(ProximityCaptureUpdateModuleData, m_requiresAllKindOfs) },
110+
{ "ForbiddenKindOf", KindOfMaskType::parseFromINI, NULL, offsetof(ProximityCaptureUpdateModuleData, m_forbiddenKindOf) },
111+
{ "AllowAirborne", INI::parseBool, NULL, offsetof(ProximityCaptureUpdateModuleData, m_isCountAirborne) },
112+
{ "UnitValueContentionDelta", INI::parseReal, NULL, offsetof(ProximityCaptureUpdateModuleData, m_unitValueContentionDelta) },
113+
{ "UnitValueCountFactor", INI::parseReal, NULL, offsetof(ProximityCaptureUpdateModuleData, m_unitValueCountFactor) },
114+
//{ "UnitValueBuildCostFactor", INI::parseReal, NULL, offsetof(ProximityCaptureUpdateModuleData, m_unitValueBuildCostFactor) },
115+
{ "ShowProgressBar", INI::parseBool, NULL, offsetof(ProximityCaptureUpdateModuleData, m_showProgressBar) },
116+
{ "CapturePingInterval", INI::parseUnsignedShort, NULL, offsetof(ProximityCaptureUpdateModuleData, m_capturePingInterval) },
117+
{ "ShowCaptureFlash", INI::parseBool, NULL, offsetof(ProximityCaptureUpdateModuleData, m_showCapturePingFlash) },
118+
{ "PlayDefectorPingSound", INI::parseBool, NULL, offsetof(ProximityCaptureUpdateModuleData, m_playDefectorPingSound) },
119+
//{ "CapturePingSound", INI::parseAudioEventRTS, NULL, offsetof(ProximityCaptureUpdateModuleData, m_capturePingSound) },
120+
{ "StartCaptureFX", INI::parseFXList, NULL, offsetof(ProximityCaptureUpdateModuleData, m_startCaptureFX) },
121+
{ "StartRemoveFX", INI::parseFXList, NULL, offsetof(ProximityCaptureUpdateModuleData, m_startUncapFX) },
122+
{ "FinishCaptureFX", INI::parseFXList, NULL, offsetof(ProximityCaptureUpdateModuleData, m_finishCaptureFX) },
123+
{ "CapturePingFX", INI::parseFXList, NULL, offsetof(ProximityCaptureUpdateModuleData, m_capturePingFX) },
124+
{ "CapturePingContestedFX", INI::parseFXList, NULL, offsetof(ProximityCaptureUpdateModuleData, m_capturePingContestedFX) },
125+
{ "SkillPointsForCapture", INI::parseInt, NULL, offsetof(ProximityCaptureUpdateModuleData, m_skillPointsForCapture) },
126+
{ 0, 0, 0, 0 }
127+
};
128+
p.add(dataFieldParse);
129+
}
130+
};
131+
132+
//-------------------------------------------------------------------------------------------------
133+
/** EnemyNear update */
134+
//-------------------------------------------------------------------------------------------------
135+
class ProximityCaptureUpdate : public UpdateModule
136+
{
137+
138+
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( ProximityCaptureUpdate, "ProximityCaptureUpdate" )
139+
MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( ProximityCaptureUpdate, ProximityCaptureUpdateModuleData )
140+
141+
public:
142+
143+
ProximityCaptureUpdate( Thing *thing, const ModuleData* moduleData );
144+
// virtual destructor prototype provided by memory pool declaration
145+
146+
virtual UpdateSleepTime update();
147+
148+
Bool getProgressBarInfo(Real& progress, Int& type, RGBAColorInt& color, RGBAColorInt& colorBG);
149+
150+
protected:
151+
152+
Int checkDominantPlayer( void );
153+
154+
void handleCaptureProgress(Int dominantPlayer);
155+
void handleFlashEffects(Int dominantPlayer);
156+
157+
Real getValueForUnit(const Object* obj) const;
158+
159+
private:
160+
161+
Int m_capturingPlayer;
162+
Int m_dominantPlayerPrev;
163+
Bool m_isContested;
164+
Real m_captureProgress;
165+
UnsignedInt m_lastTickFrame;
166+
167+
UnsignedShort m_capturePingDelay;
168+
169+
Real m_currentProgressRate; ///< current speed/direction for interpolation
170+
171+
void startCapture(Int playerId);
172+
void finishCapture(Int playerId);
173+
void startUncap(Int playerId);
174+
void finishUncap(Int playerId);
175+
176+
Real getCaptureProgressInterp();
177+
178+
};

GeneralsMD/Code/GameEngine/Source/Common/Thing/ModuleFactory.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
#include "GameLogic/Module/DynamicGeometryInfoUpdate.h"
124124
#include "GameLogic/Module/DynamicShroudClearingRangeUpdate.h"
125125
#include "GameLogic/Module/EnemyNearUpdate.h"
126+
#include "GameLogic/Module/ProximityCaptureUpdate.h"
126127
#include "GameLogic/Module/FireSpreadUpdate.h"
127128
#include "GameLogic/Module/FirestormDynamicGeometryInfoUpdate.h"
128129
#include "GameLogic/Module/FireWeaponUpdate.h"
@@ -430,6 +431,7 @@ void ModuleFactory::init( void )
430431
addModule( HordeUpdate );
431432
addModule( ToppleUpdate );
432433
addModule( EnemyNearUpdate );
434+
addModule( ProximityCaptureUpdate );
433435
addModule( LifetimeUpdate );
434436
addModule( RadiusDecalUpdate );
435437
addModule( RadiusDecalBehavior );

GeneralsMD/Code/GameEngine/Source/GameClient/FXList.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,10 +665,18 @@ class ParticleSystemFXNugget : public FXNugget
665665
{
666666
//old way:
667667
//newPos.z = TheTerrainLogic->getGrsoundHeight( newPos.x, newPos.y ) + 1;// The plus one prevents scissoring with terrain
668-
669668
//new way: now we allow bridges in the GroundHeight.
669+
//newer way: include water
670+
670671
PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(&newPos);
671-
newPos.z = TheTerrainLogic->getLayerHeight( newPos.x, newPos.y, layer );
672+
673+
if (Real waterZ = 0; TheGlobalData->m_heightAboveTerrainIncludesWater && layer == LAYER_GROUND &&
674+
TheTerrainLogic->isUnderwater(newPos.x, newPos.y, &waterZ)) {
675+
newPos.z = waterZ;
676+
}
677+
else {
678+
newPos.z = TheTerrainLogic->getLayerHeight(newPos.x, newPos.y, layer);
679+
}
672680
}
673681
else
674682
newPos.z = primary->z + offset.z + m_height.getValue();

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Object.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
#include "GameLogic/Module/UpdateModule.h"
116116
#include "GameLogic/Module/UpgradeModule.h"
117117
#include "GameLogic/Module/EnergyShieldBehavior.h"
118+
#include "GameLogic/Module/ProximityCaptureUpdate.h"
118119

119120
#include "GameLogic/Object.h"
120121
#include "GameLogic/PartitionManager.h"
@@ -1916,7 +1917,6 @@ Bool Object::getProgressBarShowingInfo(bool selected, Real& progress, Int& type,
19161917
return FALSE;
19171918

19181919
// We put every case of Progress bars here.
1919-
// Maybe we should require a KindOf for performance?
19201920

19211921
type = 0; // TODO
19221922
color = { 255, 255, 255, 255 }; // Default = white
@@ -1945,6 +1945,13 @@ Bool Object::getProgressBarShowingInfo(bool selected, Real& progress, Int& type,
19451945
return true;
19461946
}
19471947
}
1948+
else if ((*u)->getModuleNameKey() == NAMEKEY("ProximityCaptureUpdate")) {
1949+
ProximityCaptureUpdate* pcu = (ProximityCaptureUpdate*)(*u);
1950+
if (pcu->getProgressBarInfo(progress, type, color, colorBG)) {
1951+
return true;
1952+
}
1953+
1954+
}
19481955

19491956
}
19501957

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/AutoDepositUpdate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ void AutoDepositUpdate::awardInitialCaptureBonus( Player *player )
133133
moneyString.format( TheGameText->fetch( "GUI:AddCash" ), getAutoDepositUpdateModuleData()->m_initialCaptureBonus );
134134
Coord3D pos;
135135
pos.set( getObject()->getPosition() );
136-
pos.z += 10.0f; //add a little z to make it show up above the unit.
136+
pos.z += 10.0f + getAutoDepositUpdateModuleData()->m_textZOffset; //add a little z to make it show up above the unit.
137137
Color color = player->getPlayerColor() | GameMakeColor( 0, 0, 0, 230 );
138138
TheInGameUI->addFloatingText( moneyString, &pos, color );
139139
}

0 commit comments

Comments
 (0)