Skip to content

Commit a609366

Browse files
committed
2 parents b65c6e7 + bc2dbcc commit a609366

14 files changed

Lines changed: 712 additions & 63 deletions

File tree

Core/GameEngine/Include/GameClient/TerrainRoads.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ class TerrainRoadType : public MemoryPoolObject
9898
Real getTransitionEffectsHeight() { return m_transitionEffectsHeight; }
9999
Int getNumFXPerType() { return m_numFXPerType; }
100100
Real getBridgeHoleAreaPercentage() { return m_bridgeHoleAreaPercentage; }
101+
Bool isDestroyable( void ) { return m_isDestroyable; }
102+
AsciiString getBridgeObjectName( void ) { return m_bridgeObjectName; }
103+
Real getBridgeDeckHeight( void ) { return m_bridgeDeckHeight; }
104+
UnsignedInt getBridgeCollapseDuration( void ) { return m_bridgeCollapseDuration; }
105+
Real getBridgeCollapseDrop( void ) { return m_bridgeCollapseDrop; }
106+
Real getBridgeCollapseTilt( void ) { return m_bridgeCollapseTilt; }
107+
Real getBridgeCollapseStagger( void ) { return m_bridgeCollapseStagger; }
108+
UnsignedInt getBridgeRebuildDuration( void ) { return m_bridgeRebuildDuration; }
109+
Real getBridgeCollapseSingleSpanRoll( void ) { return m_bridgeCollapseSingleSpanRoll; }
110+
Real getBridgeCollapseSingleSpanDrop( void ) { return m_bridgeCollapseSingleSpanDrop; }
101111

102112
// friend access methods to be used by the road collection only!
103113
void friend_setName( AsciiString name ) { m_name = name; }
@@ -127,6 +137,18 @@ class TerrainRoadType : public MemoryPoolObject
127137
void friend_setRepairedToFXString( BodyDamageType state, Int index, AsciiString s ) { m_repairedToFXString[ state ][ index ] = s; }
128138
void friend_setTransitionEffectsHeight( Real height ) { m_transitionEffectsHeight = height; }
129139
void friend_setNumFXPerType( Int num ) { m_numFXPerType = num; }
140+
void friend_setBridgeHoleAreaPercentage( Real percentage ) { m_bridgeHoleAreaPercentage = percentage; }
141+
void friend_setDestroyable( Bool destroyable ) { m_isDestroyable = destroyable; }
142+
void friend_setBridgeObjectName( AsciiString name ) { m_bridgeObjectName = name; }
143+
void friend_setBridgeDeckHeight( Real height ) { m_bridgeDeckHeight = height; }
144+
void friend_setBridgeCollapseDuration( UnsignedInt frames ) { m_bridgeCollapseDuration = frames; }
145+
void friend_setBridgeCollapseDrop( Real drop ) { m_bridgeCollapseDrop = drop; }
146+
void friend_setBridgeCollapseTilt( Real tilt ) { m_bridgeCollapseTilt = tilt; }
147+
void friend_setBridgeCollapseStagger( Real stagger ) { m_bridgeCollapseStagger = stagger; }
148+
void friend_setBridgeRebuildDuration( UnsignedInt frames ) { m_bridgeRebuildDuration = frames; }
149+
void friend_setBridgeCollapseSingleSpanRoll( Real roll ) { m_bridgeCollapseSingleSpanRoll = roll; }
150+
void friend_setBridgeCollapseSingleSpanDrop( Real drop ) { m_bridgeCollapseSingleSpanDrop = drop; }
151+
void friend_setRadarColor( RGBColor color ) { m_radarColor = color; }
130152

131153
/// get the parsing table for INI
132154
const FieldParse *getRoadFieldParse() { return m_terrainRoadFieldParseTable; }
@@ -190,6 +212,38 @@ class TerrainRoadType : public MemoryPoolObject
190212
Int m_numFXPerType; ///< for *each* fx/ocl we will make this many of them on the bridge area
191213

192214
Real m_bridgeHoleAreaPercentage; ///< if bridge is openable/destroyable, how much % of length becomes open
215+
216+
//
217+
// non landmark bridges are drawn procedurally and are represented in the logic by an object
218+
// created from m_bridgeObjectName; when destroyable they also get the 4 targetable towers
219+
// that landmark bridges have
220+
//
221+
Bool m_isDestroyable; ///< true if this bridge can be destroyed
222+
AsciiString m_bridgeObjectName; ///< object representing the bridge span in the logic
223+
224+
//
225+
// the deck plane is the driving surface; a thick deck, girders or arches hang below it and
226+
// take away room from anything passing underneath
227+
//
228+
Real m_bridgeDeckHeight; ///< thickness of the deck below the driving surface
229+
230+
//
231+
// a sectional bridge deck is baked into a shared vertex buffer and has no skeleton, so it
232+
// cannot play a model animation. these drive a procedural fold-and-drop of the span sections
233+
// instead. all default to zero, which reproduces the old instant model swap exactly.
234+
//
235+
UnsignedInt m_bridgeCollapseDuration; ///< frames the collapse animation runs, 0 disables it
236+
Real m_bridgeCollapseDrop; ///< world units a fully collapsed section falls
237+
Real m_bridgeCollapseTilt; ///< radians a fully collapsed section folds by
238+
Real m_bridgeCollapseStagger; ///< 0..1 of the duration spent rippling out from mid span
239+
UnsignedInt m_bridgeRebuildDuration; ///< frames the rebuild animation runs, 0 disables it
240+
241+
//
242+
// a bridge short enough to resolve to a single span section has nothing to fold against, so
243+
// it banks sideways and sinks instead of hinging. a zero drop falls back to the value above.
244+
//
245+
Real m_bridgeCollapseSingleSpanRoll; ///< radians a one-span deck banks by, sign picks the side
246+
Real m_bridgeCollapseSingleSpanDrop; ///< world units a one-span deck sinks, 0 means use the normal drop
193247
};
194248

195249
//-------------------------------------------------------------------------------------------------

Core/GameEngine/Source/GameClient/Terrain/TerrainRoads.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ const FieldParse TerrainRoadType::m_terrainBridgeFieldParseTable[] =
8585
{ "TransitionToOCL", parseTransitionToOCL, nullptr, 0 },
8686
{ "TransitionToFX", parseTransitionToFX, nullptr, 0 },
8787
{ "BridgeHoleAreaPercentage", INI::parsePercentToReal, nullptr, offsetof( TerrainRoadType, m_bridgeHoleAreaPercentage) },
88+
{ "Destroyable", INI::parseBool, nullptr, offsetof( TerrainRoadType, m_isDestroyable ) },
89+
{ "BridgeObjectName", INI::parseAsciiString, nullptr, offsetof( TerrainRoadType, m_bridgeObjectName ) },
90+
{ "BridgeDeckHeight", INI::parseReal, nullptr, offsetof( TerrainRoadType, m_bridgeDeckHeight ) },
91+
{ "BridgeCollapseDuration", INI::parseDurationUnsignedInt,nullptr, offsetof( TerrainRoadType, m_bridgeCollapseDuration ) },
92+
{ "BridgeCollapseDrop", INI::parseReal, nullptr, offsetof( TerrainRoadType, m_bridgeCollapseDrop ) },
93+
{ "BridgeCollapseTilt", INI::parseAngleReal, nullptr, offsetof( TerrainRoadType, m_bridgeCollapseTilt ) },
94+
{ "BridgeCollapseStagger", INI::parsePercentToReal, nullptr, offsetof( TerrainRoadType, m_bridgeCollapseStagger ) },
95+
{ "BridgeRebuildDuration", INI::parseDurationUnsignedInt,nullptr, offsetof( TerrainRoadType, m_bridgeRebuildDuration ) },
96+
{ "BridgeCollapseSingleSpanRoll", INI::parseAngleReal, nullptr, offsetof( TerrainRoadType, m_bridgeCollapseSingleSpanRoll ) },
97+
{ "BridgeCollapseSingleSpanDrop", INI::parseReal, nullptr, offsetof( TerrainRoadType, m_bridgeCollapseSingleSpanDrop ) },
8898

8999

90100
{ nullptr, nullptr, nullptr, 0 },
@@ -219,6 +229,16 @@ TerrainRoadType::TerrainRoadType()
219229
m_radarColor.blue = 0.0f;
220230
m_transitionEffectsHeight = 0.0f;
221231
m_numFXPerType = 0;
232+
m_bridgeHoleAreaPercentage = 0.0f;
233+
m_isDestroyable = FALSE;
234+
m_bridgeDeckHeight = 0.0f;
235+
m_bridgeCollapseDuration = 0;
236+
m_bridgeCollapseDrop = 0.0f;
237+
m_bridgeCollapseTilt = 0.0f;
238+
m_bridgeCollapseStagger = 0.0f;
239+
m_bridgeRebuildDuration = 0;
240+
m_bridgeCollapseSingleSpanRoll = 0.0f;
241+
m_bridgeCollapseSingleSpanDrop = 0.0f;
222242

223243
}
224244

@@ -406,6 +426,20 @@ TerrainRoadType *TerrainRoadCollection::newBridge( AsciiString name )
406426

407427
bridge->friend_setTransitionEffectsHeight( defaultBridge->getTransitionEffectsHeight() );
408428
bridge->friend_setNumFXPerType( defaultBridge->getNumFXPerType() );
429+
bridge->friend_setBridgeHoleAreaPercentage( defaultBridge->getBridgeHoleAreaPercentage() );
430+
bridge->friend_setDestroyable( defaultBridge->isDestroyable() );
431+
bridge->friend_setBridgeObjectName( defaultBridge->getBridgeObjectName() );
432+
bridge->friend_setBridgeDeckHeight( defaultBridge->getBridgeDeckHeight() );
433+
bridge->friend_setBridgeCollapseDuration( defaultBridge->getBridgeCollapseDuration() );
434+
bridge->friend_setBridgeCollapseDrop( defaultBridge->getBridgeCollapseDrop() );
435+
bridge->friend_setBridgeCollapseTilt( defaultBridge->getBridgeCollapseTilt() );
436+
bridge->friend_setBridgeCollapseStagger( defaultBridge->getBridgeCollapseStagger() );
437+
bridge->friend_setBridgeRebuildDuration( defaultBridge->getBridgeRebuildDuration() );
438+
bridge->friend_setBridgeCollapseSingleSpanRoll( defaultBridge->getBridgeCollapseSingleSpanRoll() );
439+
bridge->friend_setBridgeCollapseSingleSpanDrop( defaultBridge->getBridgeCollapseSingleSpanDrop() );
440+
441+
// a block that omits RadarColor drew black on the radar without this
442+
bridge->friend_setRadarColor( defaultBridge->getRadarColor() );
409443
for( Int state = BODY_PRISTINE; state < BODYDAMAGETYPE_COUNT; state++ )
410444
{
411445

Core/GameEngine/Source/GameLogic/AI/AIPathfind.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "Common/ThingFactory.h"
3939

4040
#include "GameClient/Line2D.h"
41+
#include "GameClient/TerrainRoads.h"
4142

4243
#include "GameLogic/AI.h"
4344
#include "GameLogic/GameLogic.h"
@@ -4369,6 +4370,12 @@ void Pathfinder::classifyObjectFootprint( Object *obj, Bool insert )
43694370
return; // It is important to not abuse bridge towers.
43704371
}
43714372

4373+
if (obj->isKindOf(KINDOF_BRIDGE) && !obj->getTemplate()->isBridge()) {
4374+
// Procedural bridge span. Its deck is a pathfind layer of its own, and the ground below it
4375+
// is governed by the bridge clearance, not by this object's placeholder box.
4376+
return;
4377+
}
4378+
43724379
if (obj->getTemplate()->getFenceWidth() > 0.0f)
43734380
{
43744381
if (!obj->isKindOf(KINDOF_DEFENSIVE_WALL))
@@ -4861,6 +4868,10 @@ static void calculateBridgeHeights(IRegion2D bounds, PathfindCell** map)
48614868
if (cellHiX > bounds.hi.x) cellHiX = bounds.hi.x;
48624869
if (cellHiY > bounds.hi.y) cellHiY = bounds.hi.y;
48634870

4871+
// a thick deck, girders or arches hang below the driving surface and take away room
4872+
TerrainRoadType *bridgeTemplate = TheTerrainRoads->findBridge( bridge->getBridgeTemplateName() );
4873+
Real deckHeight = bridgeTemplate ? bridgeTemplate->getBridgeDeckHeight() : 0.0f;
4874+
48644875
for (Int i = cellLoX; i < cellHiX; ++i) {
48654876
for (Int j = cellLoY; j < cellHiY; ++j) {
48664877
Real worldX = ((Real)i + 0.5f) * PATHFIND_CELL_SIZE_F;
@@ -4878,12 +4889,15 @@ static void calculateBridgeHeights(IRegion2D bounds, PathfindCell** map)
48784889
continue;
48794890
}
48804891

4892+
// the deck plane through the two bridge points is what a unit passing below clears
48814893
Real bridgeZ = TheTerrainLogic->getLayerHeight(worldX, worldY, layer);
4882-
Real waterZ, groundZ;
4894+
4895+
// isUnderwater leaves waterZ untouched where there is no water, so seed both
4896+
Real waterZ = 0.0f, groundZ = 0.0f;
48834897
TheTerrainLogic->isUnderwater(worldX, worldY, &waterZ, &groundZ);
48844898
Real baseZ = (waterZ > groundZ) ? waterZ : groundZ;
48854899

4886-
Real gap = bridgeZ - baseZ;
4900+
Real gap = bridgeZ - deckHeight - baseZ;
48874901
if (gap < 0.0f) gap = 0.0f;
48884902

48894903
Int encoded = (Int)(gap / 10.0f);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct TimeAndLocationInfo
5151
{
5252
UnsignedInt delay; ///< how long to wait to execute this
5353
AsciiString boneName; ///< which bone to execute at
54+
Real spanFraction; ///< 0..1 along the bridge centreline, <0 means unset
5455
};
5556
// ------------------------------------------------------------------------------------------------
5657
struct BridgeFXInfo

GeneralsMD/Code/GameEngine/Include/GameLogic/TerrainLogic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ class Bridge : public MemoryPoolObject
210210
Bool hasHoleArea(); // check if this bridge has defined a hole area for damaged/drawbridge state
211211
Bool hasHole(); // Check if bridge currently has a hole (destroyed/drawbridge open)
212212
void setDrawBridgeStage(bool open); // change if bridge is open/closed
213+
void updateBridgeObjectGeometry(); // size the bridge object's collision box, or collapse it when the deck is gone
213214
};
214215

215216
//-------------------------------------------------------------------------------------------------

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,8 @@ void ThingTemplate::parseRequiredBridgeHeight(INI* ini, void* instance, void* st
10761076
self->m_requiredBridgeHeight = -1;
10771077
}
10781078
else {
1079-
self->m_requiredBridgeHeight = std::clamp(static_cast<byte>(value / 10.0f), static_cast<byte>(0), static_cast<byte>(15));
1079+
// rounded up, see Object::getRequiredBridgeHeight. 0 still means "never blocked".
1080+
self->m_requiredBridgeHeight = std::clamp(static_cast<byte>(REAL_TO_INT_CEIL(value / 10.0f)), static_cast<byte>(0), static_cast<byte>(15));
10801081
}
10811082
}
10821083

0 commit comments

Comments
 (0)