Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 180 additions & 6 deletions Generals/Code/GameEngine/Source/GameLogic/AI/AIPathfind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3322,6 +3322,10 @@ void PathfindLayer::doDebugIcons() {
if (m_layer == LAYER_WALL) {
bridgeHeight = TheAI->pathfinder()->getWallHeight();
}
static Int flash = 0;
flash--;
if (flash<1) flash = 20;
if (flash < 10) return;
Bool showCells = TheGlobalData->m_debugAI==AI_DEBUG_CELLS;
// show the pathfind grid
for( int j=0; j<m_height; j++ )
Expand All @@ -3333,8 +3337,8 @@ void PathfindLayer::doDebugIcons() {
topLeftCorner.x = (Real)(i+m_xOrigin) * PATHFIND_CELL_SIZE_F;

color.red = color.green = color.blue = 0;
Bool empty = true;

Bool empty = false;
Real size = 0.4f;
const PathfindCell *cell = &m_layerCells[i][j];
if (cell)
{
Expand All @@ -3344,13 +3348,16 @@ void PathfindLayer::doDebugIcons() {
empty = false;
} else if (cell->getType() == PathfindCell::CELL_IMPASSABLE) {
color.red = color.green = color.blue = 1;
size = 0.2f;
empty = false;
} else if (cell->getType() == PathfindCell::CELL_BRIDGE_IMPASSABLE) {
color.blue = color.red = 1;
empty = false;
} else if (cell->getType() == PathfindCell::CELL_CLIFF) {
color.red = 1;
empty = false;
} else {
size = 0.2f;
}
}
if (showCells) {
Expand All @@ -3376,7 +3383,7 @@ void PathfindLayer::doDebugIcons() {
loc.x = topLeftCorner.x + PATHFIND_CELL_SIZE_F/2.0f;
loc.y = topLeftCorner.y + PATHFIND_CELL_SIZE_F/2.0f;
loc.z = bridgeHeight;
addIcon(&loc, PATHFIND_CELL_SIZE_F*0.8f, 99, color);
addIcon(&loc, PATHFIND_CELL_SIZE_F*size, 99, color);
}
}
}
Expand Down Expand Up @@ -3570,7 +3577,11 @@ void PathfindLayer::classifyCells()
groundCell->setConnectLayer(LAYER_INVALID); // disconnect it.
}
}
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
cell->setType(PathfindCell::CELL_IMPASSABLE);
#else
cell->setType(PathfindCell::CELL_BRIDGE_IMPASSABLE);
#endif
}
}
}
Expand Down Expand Up @@ -3735,7 +3746,11 @@ void PathfindLayer::classifyLayerMapCell( Int i, Int j , PathfindCell *cell, Bri
cell->setType(PathfindCell::CELL_CLEAR);
} else {
if (bridgeCount!=0) {
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
cell->setType(PathfindCell::CELL_CLIFF); // it's off the bridge.
#else
cell->setType(PathfindCell::CELL_BRIDGE_IMPASSABLE); // it's off the bridge.
Comment thread
xezon marked this conversation as resolved.
#endif
}

// check against the end lines.
Expand All @@ -3746,6 +3761,7 @@ void PathfindLayer::classifyLayerMapCell( Int i, Int j , PathfindCell *cell, Bri
cellBounds.hi.x = bottomRightCorner.x;
cellBounds.hi.y = bottomRightCorner.y;

#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
if (m_bridge->isCellOnEnd(&cellBounds)) {
cell->setType(PathfindCell::CELL_CLEAR);
}
Expand All @@ -3759,6 +3775,21 @@ void PathfindLayer::classifyLayerMapCell( Int i, Int j , PathfindCell *cell, Bri
groundCell->setConnectLayer(cell->getLayer());
}
}
#else
if (m_bridge->isCellOnSide(&cellBounds)) {
cell->setType(PathfindCell::CELL_BRIDGE_IMPASSABLE);
} else {
if (m_bridge->isCellOnEnd(&cellBounds)) {
cell->setType(PathfindCell::CELL_CLEAR);
}
if (m_bridge->isCellEntryPoint(&cellBounds)) {
cell->setType(PathfindCell::CELL_CLEAR);
cell->setConnectLayer(LAYER_GROUND);
PathfindCell *groundCell = TheAI->pathfinder()->getCell(LAYER_GROUND, i, j );
groundCell->setConnectLayer(cell->getLayer());
}
}
#endif
}
Coord3D center = topLeftCorner;
center.x += PATHFIND_CELL_SIZE/2;
Expand All @@ -3771,7 +3802,11 @@ void PathfindLayer::classifyLayerMapCell( Int i, Int j , PathfindCell *cell, Bri
if (groundHeight+LAYER_Z_CLOSE_ENOUGH_F > bridgeHeight) {
PathfindCell *groundCell = TheAI->pathfinder()->getCell(LAYER_GROUND,i, j);
if (!(groundCell->getType()==PathfindCell::CELL_OBSTACLE)) {
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
groundCell->setType(PathfindCell::CELL_IMPASSABLE);
#else
groundCell->setType(PathfindCell::CELL_BRIDGE_IMPASSABLE);
#endif
}
}
}
Expand Down Expand Up @@ -3848,7 +3883,11 @@ void PathfindLayer::classifyWallMapCell( Int i, Int j , PathfindCell *cell, Obje
cell->setType(PathfindCell::CELL_CLEAR);
} else {
if (bridgeCount!=0) {
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
cell->setType(PathfindCell::CELL_CLIFF); // it's off the bridge.
#else
cell->setType(PathfindCell::CELL_BRIDGE_IMPASSABLE); // it's off the bridge.
#endif
}

}
Expand Down Expand Up @@ -4038,7 +4077,9 @@ void Pathfinder::updateLayer(Object *obj, PathfindLayerEnum layer)
*/
void Pathfinder::classifyFence( Object *obj, Bool insert )
{
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
m_zoneManager.markZonesDirty();
#endif

const Coord3D *pos = obj->getPosition();
Real angle = obj->getOrientation();
Expand All @@ -4062,6 +4103,25 @@ void Pathfinder::classifyFence( Object *obj, Bool insert )
Real tl_x = pos->x - fenceOffset*c - halfsizeY*s;
Real tl_y = pos->y + halfsizeY*c - fenceOffset*s;

#if !(RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING)
IRegion2D cellBounds;
cellBounds.lo.x = REAL_TO_INT_FLOOR((pos->x + 0.5f)/PATHFIND_CELL_SIZE_F);
cellBounds.lo.y = REAL_TO_INT_FLOOR((pos->y + 0.5f)/PATHFIND_CELL_SIZE_F);
// TheSuperHackers @fix Mauller 16/06/2025 Fixes uninitialized variables.
#if RETAIL_COMPATIBLE_CRC
//CRCDEBUG_LOG(("Pathfinder::classifyFence - (%d,%d)", cellBounds.hi.x, cellBounds.hi.y));

// In retail, the values in the stack often look like this. We set them
// to reduce the likelihood of mismatch.
cellBounds.hi.x = 253961804;
cellBounds.hi.y = 4202797;
#else
cellBounds.hi.x = REAL_TO_INT_CEIL((pos->x + 0.5f)/PATHFIND_CELL_SIZE_F);
cellBounds.hi.y = REAL_TO_INT_CEIL((pos->y + 0.5f)/PATHFIND_CELL_SIZE_F);
#endif
Bool didAnything = false;
#endif // !(RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING)

for (Int iy = 0; iy < numStepsY; ++iy, tl_x += ydx, tl_y += ydy)
{
Real x = tl_x;
Expand All @@ -4072,6 +4132,7 @@ void Pathfinder::classifyFence( Object *obj, Bool insert )
Int cy = REAL_TO_INT_FLOOR((y + 0.5f)/PATHFIND_CELL_SIZE_F);
if (cx >= 0 && cy >= 0 && cx < m_extent.hi.x && cy < m_extent.hi.y)
{
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
if (insert) {
ICoord2D pos;
pos.x = cx;
Expand All @@ -4080,9 +4141,36 @@ void Pathfinder::classifyFence( Object *obj, Bool insert )
}
else
m_map[cx][cy].removeObstacle(obj);
#else
if (insert) {
ICoord2D pos;
pos.x = cx;
pos.y = cy;
if (m_map[cx][cy].setTypeAsObstacle( obj, true, pos )) {
didAnything = true;
m_map[cx][cy].setZone(PathfindZoneManager::UNINITIALIZED_ZONE);
}
}
else {
if (m_map[cx][cy].removeObstacle(obj)) {
didAnything = true;
m_map[cx][cy].setZone(PathfindZoneManager::UNINITIALIZED_ZONE);
}
}
if (cellBounds.lo.x>cx) cellBounds.lo.x = cx;
if (cellBounds.lo.y>cy) cellBounds.lo.y = cy;
if (cellBounds.hi.x<cx) cellBounds.hi.x = cx;
if (cellBounds.hi.y<cy) cellBounds.hi.y = cy;
#endif
}
}
}
#if !(RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING)
if (didAnything) {
m_zoneManager.markZonesDirty();
m_zoneManager.updateZonesForModify(m_map, m_layers, cellBounds, m_extent);
}
#endif
}

/**
Expand Down Expand Up @@ -4117,6 +4205,12 @@ void Pathfinder::classifyObjectFootprint( Object *obj, Bool insert )
// Just in case, remove the object. Remove checks that the object has been added before
// removing, so it's safer to just remove it, as by the time some units "die", they've become
// lifeless immobile husks of debris, but we still need to remove them. jba.

#if !RTS_GENERALS
Comment thread
xezon marked this conversation as resolved.
if ( obj->isKindOf( KINDOF_BLAST_CRATER ) ) // since these footprints are permanent, never remove them
return;
#endif

removeUnitFromPathfindMap(obj);
if (obj->isKindOf(KINDOF_WALK_ON_TOP_OF_WALL)) {
if (!m_layers[LAYER_WALL].isUnused()) {
Expand Down Expand Up @@ -4160,20 +4254,35 @@ void Pathfinder::classifyObjectFootprint( Object *obj, Bool insert )
return;
}

#if RTS_GENERALS
Comment thread
xezon marked this conversation as resolved.
if (obj->getHeightAboveTerrain() > PATHFIND_CELL_SIZE_F) {
return; // Don't add bounds that are up in the air.
}
#else
if (obj->getHeightAboveTerrain() > PATHFIND_CELL_SIZE_F && ( ! obj->isKindOf( KINDOF_BLAST_CRATER ) ) )
{
return; // Don't add bounds that are up in the air.... unless a blast crater wants to do just that
}
#endif
internal_classifyObjectFootprint(obj, insert);
}

void Pathfinder::internal_classifyObjectFootprint( Object *obj, Bool insert )
{
const Coord3D *pos = obj->getPosition();

#if !(RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING)
IRegion2D cellBounds;
cellBounds.lo.x = REAL_TO_INT_FLOOR((pos->x + 0.5f)/PATHFIND_CELL_SIZE_F);
cellBounds.lo.y = REAL_TO_INT_FLOOR((pos->y + 0.5f)/PATHFIND_CELL_SIZE_F);
cellBounds.hi = cellBounds.lo;
#endif

switch(obj->getGeometryInfo().getGeomType())
{
case GEOMETRY_BOX:
{
m_zoneManager.markZonesDirty();
const Coord3D *pos = obj->getPosition();
Real angle = obj->getOrientation();

Real halfsizeX = obj->getGeometryInfo().getMajorRadius();
Expand Down Expand Up @@ -4203,6 +4312,7 @@ void Pathfinder::internal_classifyObjectFootprint( Object *obj, Bool insert )
Int cx = REAL_TO_INT_FLOOR((x + 0.5f)/PATHFIND_CELL_SIZE_F);
Int cy = REAL_TO_INT_FLOOR((y + 0.5f)/PATHFIND_CELL_SIZE_F);

#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
if (cx >= 0 && cy >= 0 && cx < m_extent.hi.x && cy < m_extent.hi.y)
{
if (insert) {
Expand All @@ -4214,6 +4324,28 @@ void Pathfinder::internal_classifyObjectFootprint( Object *obj, Bool insert )
else
m_map[cx][cy].removeObstacle(obj);
}
#else
if (cx >= 0 && cy >= 0 && cx < m_extent.hi.x && cy < m_extent.hi.y)
{
if (insert) {
ICoord2D pos;
pos.x = cx;
pos.y = cy;
if (m_map[cx][cy].setTypeAsObstacle( obj, false, pos )) {
m_map[cx][cy].setZone(PathfindZoneManager::UNINITIALIZED_ZONE);
}
}
else {
if (m_map[cx][cy].removeObstacle(obj)) {
m_map[cx][cy].setZone(PathfindZoneManager::UNINITIALIZED_ZONE);
}
}
if (cellBounds.lo.x>cx) cellBounds.lo.x = cx;
if (cellBounds.lo.y>cy) cellBounds.lo.y = cy;
if (cellBounds.hi.x<cx) cellBounds.hi.x = cx;
if (cellBounds.hi.y<cy) cellBounds.hi.y = cy;
}
#endif
}
}
}
Expand All @@ -4227,7 +4359,6 @@ void Pathfinder::internal_classifyObjectFootprint( Object *obj, Bool insert )
/// @todo This is a very inefficient circle-rasterizer
ICoord2D topLeft, bottomRight;
Coord2D center, delta;
const Coord3D *pos = obj->getPosition();
Real radius = obj->getGeometryInfo().getMajorRadius();
Real r2, size;

Expand All @@ -4252,6 +4383,7 @@ void Pathfinder::internal_classifyObjectFootprint( Object *obj, Bool insert )

if (delta.x*delta.x + delta.y*delta.y <= r2)
{
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
if (i >= 0 && j >= 0 && i < m_extent.hi.x && j < m_extent.hi.y)
{
if (insert) {
Expand All @@ -4263,20 +4395,54 @@ void Pathfinder::internal_classifyObjectFootprint( Object *obj, Bool insert )
else
m_map[i][j].removeObstacle( obj );
}
#else
if (i >= 0 && j >= 0 && i < m_extent.hi.x && j < m_extent.hi.y)
{
if (insert) {
ICoord2D pos;
pos.x = i;
pos.y = j;
if (m_map[i][j].setTypeAsObstacle( obj, false, pos )) {
m_map[i][j].setZone(PathfindZoneManager::UNINITIALIZED_ZONE);
}
}
else {
if (m_map[i][j].removeObstacle(obj)) {
m_map[i][j].setZone(PathfindZoneManager::UNINITIALIZED_ZONE);
}
}
if (cellBounds.lo.x>i) cellBounds.lo.x = i;
if (cellBounds.lo.y>j) cellBounds.lo.y = j;
if (cellBounds.hi.x<i) cellBounds.hi.x = i;
if (cellBounds.hi.y<j) cellBounds.hi.y = j;
}
#endif
}
}
}
}
break;
}

#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
Region2D bounds;
Int i, j;
obj->getGeometryInfo().get2DBounds(*obj->getPosition(), obj->getOrientation(), bounds);
IRegion2D cellBounds;
cellBounds.lo.x = REAL_TO_INT_FLOOR(bounds.lo.x/PATHFIND_CELL_SIZE_F)-1;
cellBounds.lo.y = REAL_TO_INT_FLOOR(bounds.lo.y/PATHFIND_CELL_SIZE_F)-1;
cellBounds.hi.x = REAL_TO_INT_CEIL(bounds.hi.x/PATHFIND_CELL_SIZE_F)+1;
cellBounds.hi.y = REAL_TO_INT_CEIL(bounds.hi.y/PATHFIND_CELL_SIZE_F)+1;
#else
m_zoneManager.updateZonesForModify(m_map, m_layers, cellBounds, m_extent);

cellBounds.lo.x -= 2;
cellBounds.lo.y -= 2;
cellBounds.hi.x += 2;
cellBounds.hi.y += 2;
#endif

Int i, j;

if (cellBounds.lo.x < m_extent.lo.x) {
cellBounds.lo.x = m_extent.lo.x;
}
Expand Down Expand Up @@ -4789,6 +4955,12 @@ Bool Pathfinder::checkDestination(const Object *obj, Int cellX, Int cellY, Pathf
return false;
}

#if !(RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING)
if (IS_IMPASSABLE(cell->getType())) {
return false;
}
#endif

if (cell->getFlags() == PathfindCell::NO_UNITS) {
continue; // Nobody is here, so it's ok.
}
Expand Down Expand Up @@ -4919,9 +5091,11 @@ Bool Pathfinder::checkForMovement(const Object *obj, TCheckMovementInfo &info)
if (!unit->getAIUpdateInterface()) {
return false; // can't path through not-idle units.
}
#if RTS_GENERALS && RETAIL_COMPATIBLE_PATHFINDING
if (!unit->getAIUpdateInterface()->isIdle()) {
return false; // can't path through not-idle units.
}
#endif
Bool found = false;
Int k;
for (k=0; k<numAlly; k++) {
Expand Down
Loading
Loading