Home » MODDING HQ 1.13 » v1.13 Coding Talk » Roof climbing problem in 1.13
Roof climbing problem in 1.13[message #344502]
|
Sun, 13 March 2016 10:44
|
|
Deleted. |
 |
Messages:2656
Registered:December 2012 Location: Russian Federation |
|
|
1. In 1.13, roof climbing used ASTAR.
2. At some moment, ASTAR was disabled.
3. As a result, roof climbing is partially broken now.
4. As solution, all functions that use ASTAR should be reverted to vanilla state.
For example, FindClosestClimbPoint in FindLocations.cpp:
// 0verhaul: This function is optimized to take advantage of the new climb point info.
if (gpWorldLevelData[ sGridNo].ubExtFlags[0] & MAPELEMENT_EXT_CLIMBPOINT)
MAPELEMENT_EXT_CLIMBPOINT is set in void AStarPathfinder::ExecuteAStarLogic(), which is disabled.
So, all functions that use MAPELEMENT_EXT_CLIMBPOINT should be reverted to vanilla state:
FindClosestClimbPoint, FindDirectionForClimbing
Another problem:
in GenerateBuilding (Buildings.cpp), the following code is used:
if ( !(gpWorldLevelData[ sCurrGridNo ].ubExtFlags[0] & MAPELEMENT_EXT_ROOFCODE_VISITED) )
{
gpWorldLevelData[ sCurrGridNo ].ubExtFlags[0] |= MAPELEMENT_EXT_ROOFCODE_VISITED;
gubBuildingInfo[ sCurrGridNo ] = ubBuildingID;
// consider this location as possible climb gridno
// there must be a regular wall adjacent to this for us to consider it a
// climb gridno
What is interesting is
gubBuildingInfo[ sCurrGridNo ] = ubBuildingID;
which sets building information for the tile that is outside of the building. As a result, all tiles adjacent to building are set as they belong to that building, as a result, SameBuilding returns TRUE when first gridno is inside building and second gridno is outside of the building.
There's no such code in vanilla source, this looks like some old 1.13 bug.
Another problem:
when AI tries to find a path to a disturbance on different level, it first searches for a closest climb point.
Then, if the climbing point is found, it tries to estimate path cost to climb point, at which moment it fails if the soldier is already standing at the climb point, because EstimatePathCostToLocation returns 0.
This means that if AI was moving to climb and reached the climb point, next turn instead of climbing he moves to another climb point or simply decides taking cover or something else, because his seacrh for closest disturbance call fails.
--------------------------------------------------------------------------------------------------------------
My solution to some probems, implemented and tested in ja2+ai:
in Buildings.cpp/FindClosestClimbPoint:
allow climbing from the spot where soldier stands:
Toggle Spoiler for ( ubLoop = 0; ubLoop < ubNumClimbSpots; ubLoop++ )
{
if( (WhoIsThere2( pBuilding->sUpClimbSpots[ ubLoop ], 0 ) == NOBODY ||
WhoIsThere2( pBuilding->sUpClimbSpots[ ubLoop ], 0 ) == pSoldier->ubID ) &&
(WhoIsThere2( pBuilding->sDownClimbSpots[ ubLoop ], 1 ) == NOBODY ||
WhoIsThere2( pBuilding->sDownClimbSpots[ ubLoop ], 1 ) == pSoldier->ubID) &&
!InGas( pSoldier, psClimbSpots[ ubLoop] ) &&
!Water( psClimbSpots[ ubLoop], pSoldier->pathing.bLevel) )
{
sDistance = PythSpacesAway( sStartGridNo, psClimbSpots[ ubLoop ] );
if (sDistance < sClosestDistance )
{
sClosestDistance = sDistance;
sClosestSpot = psClimbSpots[ ubLoop ];
}
}
}
In AIUtils.cpp/EstimatePathCostToLocation:
don't return 0 if soldier is standing at climb point:
Toggle SpoilersPathCost = PlotPath( pSoldier, sClimbGridNo, FALSE, FALSE, FALSE, WALKING, FALSE, FALSE, 0 );
// sevenfm: check if we are already standing at climb gridno
if (sPathCost != 0 || pSoldier->sGridNo == sClimbGridNo)
{
// add in cost of climbing down
if (fAddCostAfterClimbingUp)
{
// add in cost of later climbing up, too
sPathCost += APBPConstants[AP_CLIMBOFFROOF] + APBPConstants[AP_CLIMBROOF];
// add in an estimate of getting there after climbing down
sPathCost += (APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK]) * PythSpacesAway( sClimbGridNo, sDestGridNo );
}
else
{
sPathCost += APBPConstants[AP_CLIMBOFFROOF];
// add in an estimate of getting there after climbing down, *but not on top of roof*
sPathCost += (APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK]) * PythSpacesAway( sClimbGridNo, sDestGridNo ) / 2;
}
*pfClimbingNecessary = TRUE;
*psClimbGridNo = sClimbGridNo;
}
sPathCost = PlotPath( pSoldier, sClimbGridNo, FALSE, FALSE, FALSE, WALKING, FALSE, FALSE, 0);
// sevenfm: check if we are already standing at climb gridno
if (sPathCost != 0 || pSoldier->sGridNo == sClimbGridNo)
{
// add in the cost of climbing up or down
if (pSoldier->pathing.bLevel == 0)
{
// must climb up
sPathCost += APBPConstants[AP_CLIMBROOF];
if (fAddCostAfterClimbingUp)
{
// add to path a rough estimate of how far to go from the climb gridno to the friend
// estimate walk cost
sPathCost += (APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK]) * PythSpacesAway( sClimbGridNo, sDestGridNo );
}
}
else
{
// must climb down
sPathCost += APBPConstants[AP_CLIMBOFFROOF];
// add to path a rough estimate of how far to go from the climb gridno to the friend
// estimate walk cost
sPathCost += (APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK]) * PythSpacesAway( sClimbGridNo, sDestGridNo );
}
*pfClimbingNecessary = TRUE;
*psClimbGridNo = sClimbGridNo;
}
FindLocations.cpp/FindClosestClimbPoint: new calculation using FindHeigherLevel
Toggle SpoilerINT32 FindClosestClimbPoint (SOLDIERTYPE *pSoldier, BOOLEAN fClimbUp )
{
INT32 sBestSpot = NOWHERE;
// sevenfm: safety check
if(!pSoldier)
{
return NOWHERE;
}
//DebugMsg( TOPIC_JA2AI , DBG_LEVEL_3 , "FindClosestClimbPoint");
if (fClimbUp)
{
// For the climb up case, search the nearby limits for a climb up point and take the closest.
INT32 sGridNo;
static const INT32 iSearchRange = 20;
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
//UINT8 ubTestDir;
INT8 ubClimbDir;
INT32 sClimbSpot;
// determine maximum horizontal limits
sMaxLeft = min( iSearchRange, (pSoldier->sGridNo % MAXCOL));
//NumMessage("sMaxLeft = ",sMaxLeft);
sMaxRight = min( iSearchRange, MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
//NumMessage("sMaxRight = ",sMaxRight);
// determine maximum vertical limits
sMaxUp = min( iSearchRange, (pSoldier->sGridNo / MAXROW));
//NumMessage("sMaxUp = ",sMaxUp);
sMaxDown = min( iSearchRange, MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
//NumMessage("sMaxDown = ",sMaxDown);
//DebugMsg( TOPIC_JA2AI , DBG_LEVEL_3 , String("Max: Left %d Right %d Up %d Down %d", sMaxLeft, sMaxRight, sMaxUp, sMaxDown ) );
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
{
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
{
// calculate the next potential gridno
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
//DebugMsg( TOPIC_JA2AI , DBG_LEVEL_3 , String("Checking grid %d" , sGridNo ));
//NumMessage("Testing gridno #",gridno);
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
{
continue;
}
if ( sGridNo == pSoldier->pathing.sBlackList )
{
continue;
}
// exclude locations with tear/mustard gas (at this point, smoke is cool!)
if ( InGas( pSoldier, sGridNo ) )
{
continue;
}
// exclude water tiles
if ( Water( sGridNo, pSoldier->pathing.bLevel ) )
{
continue;
}
// check that there's noone at sGridNo at level 0 (this soldier is allowed)
if( WhoIsThere2( sGridNo, 0 ) != NOBODY &&
WhoIsThere2( sGridNo, 0 ) != pSoldier->ubID )
{
continue;
}
if( FindHeigherLevel( pSoldier, sGridNo, pSoldier->ubDirection, &ubClimbDir ) )
{
// ubClimbDir is new direction
// check that there's noone there
sClimbSpot = NewGridNo( sGridNo, DirectionInc( ubClimbDir));
if( WhoIsThere2( sClimbSpot, 1 ) == NOBODY )
{
// Good climb point. Is it closer than the previous point?
if( TileIsOutOfBounds(sBestSpot) ||
GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo , sGridNo ) < GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo , sBestSpot ))
{
// If not, we have a new winnar!
sBestSpot = sGridNo;
}
}
}
}
}
}
else
{
// Climbing down is easier. Just find the nearest climb point ;)
sBestSpot = FindClosestClimbPoint( pSoldier, pSoldier->sGridNo, pSoldier->sGridNo, fClimbUp);
}
// DebugMsg( TOPIC_JA2AI , DBG_LEVEL_3 , String("FindClosestClimbPoint Returning %d", sBestSpot ));
return( sBestSpot );
}
FindLocations.cpp/FindDirectionForClimbing: new calculation using FindHeigherLevel/FindLowerLevel
Toggle SpoilerINT8 FindDirectionForClimbing( SOLDIERTYPE *pSoldier, INT32 sGridNo )
{
INT8 ubClimbDir;
INT32 sClimbSpot;
if(!pSoldier)
{
return DIRECTION_IRRELEVANT;
}
if (pSoldier->pathing.bLevel == 0)
{
// check climb up
if( FindHeigherLevel( pSoldier, sGridNo, pSoldier->ubDirection, &ubClimbDir ) )
{
// ubClimbDir is new direction
// check that there's noone there
sClimbSpot = NewGridNo( sGridNo, DirectionInc( ubClimbDir));
if( WhoIsThere2( sClimbSpot, 1 ) == NOBODY &&
!Water(sClimbSpot, 1) )
{
return ubClimbDir;
}
}
}
else
{
// check climb down
if( FindLowerLevel( pSoldier, pSoldier->sGridNo, pSoldier->ubDirection, &ubClimbDir ) )
{
// ubClimbDir is new direction
sClimbSpot = NewGridNo( sGridNo, DirectionInc( ubClimbDir));
if( WhoIsThere2( sClimbSpot, 0 ) == NOBODY &&
!Water(sClimbSpot, 0) )
{
return ubClimbDir;
}
}
}
return DIRECTION_IRRELEVANT;
}
Hope that helps.
[Updated on: Sun, 13 March 2016 10:47]
Left this community.Report message to a moderator
|
|
|
|
Goto Forum:
Current Time: Wed Feb 19 01:41:05 GMT+2 2025
Total time taken to generate the page: 0.00665 seconds
|