383 lines
16 KiB
C++
383 lines
16 KiB
C++
/*
|
|
** Command & Conquer Generals(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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// (c) 2001-2003 Electronic Arts Inc. //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// FILE: TerrainLogic.h ///////////////////////////////////////////////////////////////////////////
|
|
// Logical terrain representation for the game logic side
|
|
// Author: Colin Day, April 2001
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma once
|
|
|
|
#ifndef __TERRAINLOGIC_H_
|
|
#define __TERRAINLOGIC_H_
|
|
|
|
#include "Common/GameMemory.h"
|
|
#include "Common/Snapshot.h"
|
|
#include "Common/STLTypedefs.h"
|
|
#include "GameClient/TerrainRoads.h"
|
|
|
|
typedef std::vector<ICoord2D> VecICoord2D;
|
|
|
|
class DataChunkInput;
|
|
struct DataChunkInfo;
|
|
class MapObject;
|
|
class Object;
|
|
class Dict;
|
|
class PolygonTrigger;
|
|
class ThingTemplate;
|
|
class Vector3;
|
|
class Drawable;
|
|
class Matrix3D;
|
|
class WaterHandle;
|
|
class Xfer;
|
|
|
|
enum WaypointID
|
|
{
|
|
INVALID_WAYPOINT_ID = 0x7FFFFFFF
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Waypoint
|
|
/** Helper class for waypoint info in terrain logic.
|
|
*/
|
|
class Waypoint : public MemoryPoolObject
|
|
{
|
|
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(Waypoint, "Waypoint")
|
|
|
|
// friends do not play well with MPO (srj)
|
|
//friend class TerrainLogic;
|
|
public:
|
|
Waypoint(WaypointID id, AsciiString name, const Coord3D *pLoc, AsciiString label1,
|
|
AsciiString label2, AsciiString label3, Bool biDirectional);
|
|
//~Waypoint();
|
|
enum {MAX_LINKS=8};
|
|
|
|
protected:
|
|
WaypointID m_id; ///< Unique integer identifier.
|
|
AsciiString m_name; ///< Name.
|
|
Coord3D m_location; ///< Location.
|
|
Waypoint* m_pNext; ///< Linked list of all waypoints.
|
|
Waypoint* m_links[MAX_LINKS]; ///< Directed graph of waypoints.
|
|
Int m_numLinks; ///< Number of links in m_links.
|
|
AsciiString m_pathLabel1;
|
|
AsciiString m_pathLabel2;
|
|
AsciiString m_pathLabel3;
|
|
Bool m_biDirectional;
|
|
|
|
public:
|
|
// should be protected, but friendly access needed (srj)
|
|
void setNext(Waypoint *pNext) {m_pNext = pNext; }
|
|
//void setLink(Int ndx, Waypoint *pLink)
|
|
//{
|
|
// if (ndx>=0 && ndx <=MAX_LINKS) m_links[ndx] = pLink;
|
|
//}
|
|
void addLink(Waypoint* pLink)
|
|
{
|
|
if (m_numLinks < MAX_LINKS)
|
|
{
|
|
m_links[m_numLinks] = pLink;
|
|
++m_numLinks;
|
|
}
|
|
}
|
|
|
|
public:
|
|
/// Enumerate all waypoints using getNext.
|
|
Waypoint *getNext(void) const {return m_pNext; }
|
|
/// Enumerate the directed links from a waypoint using this,a nd getLink.
|
|
Int getNumLinks(void) const {return m_numLinks; }
|
|
/// Get the n'th directed link. (May be NULL).
|
|
Waypoint *getLink(Int ndx) const {if (ndx>=0 && ndx <= MAX_LINKS) return m_links[ndx]; return NULL; }
|
|
/// Get the waypoint's name.
|
|
AsciiString getName(void) const {return m_name; }
|
|
/// Get the integer id.
|
|
WaypointID getID(void) const {return m_id; }
|
|
/// Get the waypoint's position
|
|
const Coord3D *getLocation( void ) const { return &m_location; }
|
|
/// Get the waypoint's first path label
|
|
AsciiString getPathLabel1( void ) const { return m_pathLabel1; }
|
|
/// Get the waypoint's second path label
|
|
AsciiString getPathLabel2( void ) const { return m_pathLabel2; }
|
|
/// Get the waypoint's third path label
|
|
AsciiString getPathLabel3( void ) const { return m_pathLabel3; }
|
|
/// Get bi-directionality.
|
|
Bool getBiDirectional( void ) const { return m_biDirectional; }
|
|
|
|
void setLocationZ(Real z) { m_location.z = z; }
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Bridge
|
|
/** Helper class for bridge info in terrain logic.
|
|
*/
|
|
class BridgeInfo
|
|
{
|
|
public:
|
|
BridgeInfo();
|
|
|
|
public:
|
|
Coord3D from, to; /// The points that the bridge was drawn using.
|
|
Real bridgeWidth; /// Width of the bridge.
|
|
Coord3D fromLeft, fromRight, toLeft, toRight; /// The 4 corners of the rectangle that the bridge covers.
|
|
Int bridgeIndex; ///< The index to the drawable bridges.
|
|
BodyDamageType curDamageState;
|
|
ObjectID bridgeObjectID;
|
|
ObjectID towerObjectID[ BRIDGE_MAX_TOWERS ];
|
|
Bool damageStateChanged;
|
|
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// Bridge
|
|
/** Helper class for bridge info in terrain logic.
|
|
*/
|
|
struct TBridgeAttackInfo
|
|
{
|
|
public:
|
|
Coord3D attackPoint1, attackPoint2; /// The points that can be attacked..
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------------------------------
|
|
class Bridge : public MemoryPoolObject
|
|
{
|
|
MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(Bridge, "Bridge")
|
|
// friends do not play well with MPO (srj)
|
|
//friend class TerrainLogic;
|
|
public:
|
|
|
|
public: // ctor/dtor.
|
|
Bridge(BridgeInfo &theInfo, Dict *props, AsciiString bridgeTemplateName);
|
|
Bridge(Object *bridgeObj);
|
|
//~Bridge();
|
|
|
|
protected:
|
|
Bridge* m_next; ///< Link for traversing all bridges in the current map.
|
|
AsciiString m_templateName; ///< bridge template name
|
|
BridgeInfo m_bridgeInfo;
|
|
Region2D m_bounds; /// 2d bounds for quick screening.
|
|
PathfindLayerEnum m_layer; ///< Pathfind layer for this bridge.
|
|
|
|
public:
|
|
// should be protected, but friendly access needed (srj)
|
|
void setNext(Bridge *pNext) {m_next = pNext; }
|
|
Object *createTower( Coord3D *worldPos, BridgeTowerType towerPos,
|
|
const ThingTemplate *towerTemplate, Object *bridge );
|
|
|
|
public:
|
|
/// return the bridge template name
|
|
AsciiString getBridgeTemplateName( void ) { return m_templateName; }
|
|
/// Enumerate all bridges using getNext;
|
|
Bridge *getNext(void) {return m_next; }
|
|
/// Get the height for an object on bridge. Note - assumes object is on bridge. Use isPointOnBridge to check.
|
|
Real getBridgeHeight(const Coord3D *pLoc, Coord3D* normal);
|
|
/// Get the bridges logical info.
|
|
void getBridgeInfo(class BridgeInfo *pInfo) {*pInfo = m_bridgeInfo; }
|
|
/// See if the point is on the bridge.
|
|
Bool isPointOnBridge(const Coord3D *pLoc);
|
|
Drawable *pickBridge(const Vector3 &from, const Vector3 &to, Vector3 *pos);
|
|
void updateDamageState(void); ///< Updates a bridge's damage info.
|
|
inline const BridgeInfo *peekBridgeInfo(void) const {return &m_bridgeInfo;}
|
|
inline PathfindLayerEnum getLayer(void) const {return m_layer;}
|
|
inline void setLayer(PathfindLayerEnum layer) {m_layer = layer;}
|
|
const Region2D *getBounds(void) const {return &m_bounds;}
|
|
Bool isCellOnEnd(const Region2D *cell); // Is pathfind cell on the sides of the bridge
|
|
Bool isCellOnSide(const Region2D *cell); // Is pathfind cell on the end of the bridge
|
|
Bool isCellEntryPoint(const Region2D *cell); // Is pathfind cell an entry point to the bridge
|
|
|
|
inline void setBridgeObjectID( ObjectID id ) { m_bridgeInfo.bridgeObjectID = id; }
|
|
inline void setTowerObjectID( ObjectID id, BridgeTowerType which ) { m_bridgeInfo.towerObjectID[ which ] = id; }
|
|
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
/** Device independent implementation for some functionality of the
|
|
* logical terrain singleton */
|
|
//-------------------------------------------------------------------------------------------------
|
|
class TerrainLogic : public Snapshot,
|
|
public SubsystemInterface
|
|
{
|
|
|
|
public:
|
|
|
|
TerrainLogic();
|
|
virtual ~TerrainLogic();
|
|
|
|
virtual void init( void ); ///< Init
|
|
virtual void reset( void ); ///< Reset
|
|
virtual void update( void ); ///< Update
|
|
|
|
virtual Bool loadMap( AsciiString filename, Bool query );
|
|
virtual void newMap( Bool saveGame ); ///< Initialize the logic for new map.
|
|
|
|
virtual Real getGroundHeight( Real x, Real y, Coord3D* normal = NULL ) const;
|
|
virtual Real getLayerHeight(Real x, Real y, PathfindLayerEnum layer, Coord3D* normal = NULL, Bool clip = true) const;
|
|
virtual void getExtent( Region3D *extent ) const { DEBUG_CRASH(("not implemented")); } ///< @todo This should not be a stub - this should own this functionality
|
|
virtual void getExtentIncludingBorder( Region3D *extent ) const { DEBUG_CRASH(("not implemented")); } ///< @todo This should not be a stub - this should own this functionality
|
|
virtual void getMaximumPathfindExtent( Region3D *extent ) const { DEBUG_CRASH(("not implemented")); } ///< @todo This should not be a stub - this should own this functionality
|
|
virtual Coord3D findClosestEdgePoint( const Coord3D *closestTo ) const ;
|
|
virtual Coord3D findFarthestEdgePoint( const Coord3D *farthestFrom ) const ;
|
|
virtual Bool isClearLineOfSight(const Coord3D& pos, const Coord3D& posOther) const;
|
|
|
|
virtual AsciiString getSourceFilename( void ) { return m_filenameString; }
|
|
|
|
virtual PathfindLayerEnum alignOnTerrain( Real angle, const Coord3D& pos, Bool stickToGround, Matrix3D& mtx);
|
|
|
|
virtual Bool isUnderwater( Real x, Real y, Real *waterZ = NULL, Real *terrainZ = NULL ); ///< is point under water
|
|
virtual Bool isCliffCell( Real x, Real y) const; ///< is point cliff cell
|
|
virtual const WaterHandle* getWaterHandle( Real x, Real y ); ///< get water handle at this location
|
|
virtual const WaterHandle* getWaterHandleByName( AsciiString name ); ///< get water handle by name
|
|
virtual Real getWaterHeight( const WaterHandle *water ); ///< get height of water table
|
|
virtual void setWaterHeight( const WaterHandle *water,
|
|
Real height,
|
|
Real damageAmount,
|
|
Bool forcePathfindUpdate ); ///< set height of water table
|
|
virtual void changeWaterHeightOverTime( const WaterHandle *water,
|
|
Real finalHeight,
|
|
Real transitionTimeInSeconds,
|
|
Real damageAmount );///< change water height over time
|
|
|
|
virtual Waypoint *getFirstWaypoint(void) { return m_waypointListHead; }
|
|
|
|
/// Return the waypoint with the given name
|
|
virtual Waypoint *getWaypointByName( AsciiString name );
|
|
|
|
/// Return the waypoint with the given ID
|
|
virtual Waypoint *getWaypointByID( UnsignedInt id );
|
|
|
|
/// Return the closest waypoint on the labeled path
|
|
virtual Waypoint *getClosestWaypointOnPath( const Coord3D *pos, AsciiString label );
|
|
|
|
/// Return true if the waypoint path containint pWay is labeled with the label.
|
|
virtual Bool isPurposeOfPath( Waypoint *pWay, AsciiString label );
|
|
|
|
/// Return the trigger area with the given name
|
|
virtual PolygonTrigger *getTriggerAreaByName( AsciiString name );
|
|
|
|
///Gets the first bridge. Traverse all bridges using bridge->getNext();
|
|
virtual Bridge *getFirstBridge(void) const { return m_bridgeListHead; }
|
|
|
|
/// Find the bridge at a location. NULL means no bridge.
|
|
virtual Bridge *findBridgeAt(const Coord3D *pLoc) const;
|
|
|
|
/// Find the bridge at a location. NULL means no bridge. Note that the layer value will be used to resolve crossing bridges.
|
|
virtual Bridge *findBridgeLayerAt(const Coord3D *pLoc, PathfindLayerEnum layer, Bool clip = true) const;
|
|
|
|
/// Returns true if the object is close enough to interact with the bridge for pathfinding.
|
|
virtual Bool objectInteractsWithBridgeLayer(Object *obj, Int layer, Bool considerBridgeHealth = true) const;
|
|
|
|
/// Returns true if the object is close to one or the other end of the bridge.
|
|
virtual Bool objectInteractsWithBridgeEnd(Object *obj, Int layer) const;
|
|
|
|
virtual Drawable *pickBridge(const Vector3 &from, const Vector3 &to, Vector3 *pos);
|
|
|
|
virtual void addBridgeToLogic(BridgeInfo *pInfo, Dict *props, AsciiString bridgeTemplateName); ///< Adds a bridge's logical info.
|
|
virtual void addLandmarkBridgeToLogic(Object *bridgeObj); ///< Adds a bridge's logical info.
|
|
virtual void deleteBridge( Bridge *bridge ); ///< remove a bridge
|
|
|
|
virtual void updateBridgeDamageStates(void); ///< Updates bridge's damage info.
|
|
|
|
Bool anyBridgesDamageStatesChanged(void) {return m_bridgeDamageStatesChanged; } ///< Bridge damage states updated.
|
|
Bool isBridgeRepaired(const Object *bridge); ///< Is bridge repaired?
|
|
Bool isBridgeBroken(const Object *bridge); ///< Is bridge Broken?
|
|
void getBridgeAttackPoints(const Object *bridge, TBridgeAttackInfo *info); ///< Get bridge attack points.
|
|
|
|
PathfindLayerEnum getLayerForDestination(const Coord3D *pos);
|
|
|
|
// this is just like getLayerForDestination, but always return the highest layer that will be <= z at that point
|
|
// (unlike getLayerForDestination, which will return the closest layer)
|
|
PathfindLayerEnum getHighestLayerForDestination(const Coord3D *pos, Bool onlyHealthyBridges = false);
|
|
|
|
void enableWaterGrid( Bool enable ); ///< enable/disable the water grid
|
|
|
|
// This is stuff to get the currently active boundary information
|
|
Int getActiveBoundary(void) { return m_activeBoundary; }
|
|
void setActiveBoundary(Int newActiveBoundary);
|
|
|
|
void flattenTerrain(Object *obj); ///< Flatten the terrain under a building.
|
|
|
|
protected:
|
|
|
|
// snapshot methods
|
|
virtual void crc( Xfer *xfer );
|
|
virtual void xfer( Xfer *xfer );
|
|
virtual void loadPostProcess( void );
|
|
|
|
/// Chunk parser callback.
|
|
static Bool parseWaypointDataChunk(DataChunkInput &file, DataChunkInfo *info, void *userData);
|
|
/// Chunk parser callback.
|
|
Bool parseWaypointData(DataChunkInput &file, DataChunkInfo *info, void *userData);
|
|
/// Add a waypoint to the list.
|
|
void addWaypoint(MapObject *pMapObj);
|
|
/// Add a directed link between waypoints.
|
|
void addWaypointLink(Int id1, Int id2);
|
|
/// Deletes all waypoints.
|
|
void deleteWaypoints(void);
|
|
/// Deletes all bridges.
|
|
void deleteBridges(void);
|
|
|
|
/// find the axis aligned region bounding the water table
|
|
void findAxisAlignedBoundingRect( const WaterHandle *waterHandle, Region3D *region );
|
|
|
|
UnsignedByte *m_mapData; ///< array of height samples
|
|
Int m_mapDX; ///< width of map samples
|
|
Int m_mapDY; ///< height of map samples
|
|
|
|
VecICoord2D m_boundaries;
|
|
Int m_activeBoundary;
|
|
|
|
Waypoint *m_waypointListHead;
|
|
Bridge *m_bridgeListHead;
|
|
|
|
Bool m_bridgeDamageStatesChanged;
|
|
|
|
AsciiString m_filenameString; ///< filename for terrain data
|
|
|
|
Bool m_waterGridEnabled; ///< TRUE when water grid is enabled
|
|
|
|
static WaterHandle m_gridWaterHandle; ///< water handle for the grid water (we only presently have one)
|
|
|
|
//
|
|
// we will force a limit of MAX_DYNAMIC_WATER as the max dynamically changable water
|
|
// tables for a map. We could use a list, but eh, this is fine and small anyway
|
|
//
|
|
enum { MAX_DYNAMIC_WATER = 64 };
|
|
struct DynamicWaterEntry
|
|
{
|
|
const WaterHandle *waterTable; ///< handle to water table to edit
|
|
Real changePerFrame; ///< how much height to add to the water each frame (negative=lowering)
|
|
Real targetHeight; ///< the target height we want to be at
|
|
Real damageAmount; ///< amount of damage to do to objects that are underwater
|
|
Real currentHeight; ///< we need to keep track of this ourselves cause some water height are represented with ints
|
|
} m_waterToUpdate[ MAX_DYNAMIC_WATER ]; ///< water tables to dynamicall update
|
|
Int m_numWaterToUpdate; ///< how many valid entries are in m_waterToUpdate
|
|
|
|
}; // end class TerrainLogic
|
|
|
|
// EXTERNALS //////////////////////////////////////////////////////////////////////////////////////
|
|
extern TerrainLogic *TheTerrainLogic; ///< singleton definition
|
|
|
|
extern void makeAlignToNormalMatrix( Real angle, const Coord3D& pos, const Coord3D& normal, Matrix3D& mtx);
|
|
extern Bool LineInRegion( const Coord2D *p1, const Coord2D *p2, const Region2D *clipRegion );
|
|
#endif // end __TERRAINLOGIC_H_
|