Improved code to avoid dangerous locations.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8756 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Sevenfm
2020-02-16 14:08:47 +00:00
parent 8e9f9cb8a1
commit 0330e6c1a8
5 changed files with 227 additions and 114 deletions
+147 -10
View File
@@ -945,16 +945,22 @@ INT16 RandomFriendWithin(SOLDIERTYPE *pSoldier)
continue;
}
// if our movement range is NOT restricted
if (!fRangeRestricted || (SpacesAway(usOrigin,usDest) <= usMaxDist))
if (SpacesAway(usOrigin, usDest) > usMaxDist)
{
if (LegalNPCDestination(pSoldier,usDest,ENSURE_PATH,NOWATER, 0))
{
fFound = TRUE; // found a spot
pSoldier->aiData.usActionData = usDest; // store this->pathing.sDestination
pSoldier->pathing.bPathStored = TRUE; // optimization - Ian
break; // stop checking in other directions
}
continue;
}
if (!CheckNPCDestination(pSoldier, usDest, TRUE, TRUE))
{
continue;
}
if (LegalNPCDestination(pSoldier, usDest, ENSURE_PATH, NOWATER, 0))
{
fFound = TRUE; // found a spot
pSoldier->aiData.usActionData = usDest; // store this->pathing.sDestination
pSoldier->pathing.bPathStored = TRUE; // optimization - Ian
break; // stop checking in other directions
}
}
}
@@ -1109,6 +1115,12 @@ INT32 RandDestWithinRange(SOLDIERTYPE *pSoldier)
continue;
}
if (!CheckNPCDestination(pSoldier, sRandDest, TRUE, TRUE))
{
sRandDest = NOWHERE;
continue;
}
if (!LegalNPCDestination(pSoldier,sRandDest,ENSURE_PATH,NOWATER,0))
{
sRandDest = NOWHERE;
@@ -4212,6 +4224,47 @@ UINT8 CountTeamSeeSoldier( INT8 bTeam, SOLDIERTYPE *pSoldier )
return ubFriends;
}
BOOLEAN CheckDoorAtGridno(UINT32 usGridNo)
{
STRUCTURE *pStructure;
pStructure = FindStructure(usGridNo, STRUCTURE_ANYDOOR);
if (pStructure != NULL)
{
return TRUE;
}
return FALSE;
}
BOOLEAN CheckDoorNearGridno(UINT32 usGridNo)
{
UINT8 ubMovementCost;
INT32 sTempGridNo;
UINT8 ubDirection;
if (CheckDoorAtGridno(usGridNo))
{
return TRUE;
}
for (ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ubDirection++)
{
sTempGridNo = NewGridNo(usGridNo, DirectionInc(ubDirection));
if (sTempGridNo != usGridNo)
{
ubMovementCost = gubWorldMovementCosts[sTempGridNo][ubDirection][0];
if (IS_TRAVELCOST_DOOR(ubMovementCost))
{
return TRUE;
}
}
}
return FALSE;
}
BOOLEAN FindBombNearby( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDistance )
{
UINT32 uiBombIndex;
@@ -4361,6 +4414,34 @@ BOOLEAN CheckRoof(INT32 sGridNo)
return FALSE;
}
BOOLEAN FindNearbyExplosiveStructure(INT32 sSpot, INT8 bLevel)
{
INT32 sTempGridNo;
UINT8 ubDirection;
if (TileIsOutOfBounds(sSpot))
{
return 0;
}
// check adjacent reachable tiles
for (ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ubDirection++)
{
sTempGridNo = NewGridNo(sSpot, DirectionInc(ubDirection));
if (sTempGridNo != sSpot)
{
if (FindStructFlag(sTempGridNo, bLevel, STRUCTURE_EXPLOSIVE))
{
return TRUE;
}
}
}
return FALSE;
}
UINT8 TerrainDensity(INT32 sSpot, INT8 bLevel, UINT8 ubDistance, BOOLEAN fGrass)
{
if (TileIsOutOfBounds(sSpot))
@@ -4619,4 +4700,60 @@ BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier)
return FALSE;
return TRUE;
}
}
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight)
{
if (!pSoldier)
return 0;
if (TileIsOutOfBounds(sGridNo))
return 0;
BOOLEAN fCautious = FALSE;
BOOLEAN fGreen = FALSE;
UINT8 ubLevel = 0;
if ((pSoldier->aiData.bAlertStatus >= STATUS_RED || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE))
fCautious = TRUE;
if (pSoldier->aiData.bAlertStatus < STATUS_YELLOW)
fGreen = TRUE;
if (!gGameExternalOptions.fAITacticalRetreat && NorthSpot(sGridNo, pSoldier->pathing.bLevel) ||
pSoldier->ubProfile == NO_PROFILE && fGreen && CheckDoorNearGridno(sGridNo))
ubLevel = 1;
if (fCautious && (fCheckLight && InLightAtNight(sGridNo, pSoldier->pathing.bLevel) || FindNearbyExplosiveStructure(sGridNo, pSoldier->pathing.bLevel)))
ubLevel = 2;
if (fCheckWater && DeepWater(sGridNo, pSoldier->pathing.bLevel) ||
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
ubLevel = 3;
if (InGas(pSoldier, sGridNo) ||
FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
ubLevel = 4;
return ubLevel;
}
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight)
{
if (!pSoldier)
return FALSE;
if (TileIsOutOfBounds(sGridNo))
return FALSE;
// find current danger level
UINT8 ubLevel = SpotDangerLevel(pSoldier, pSoldier->sGridNo, fCheckWater, fCheckLight);
// find danger level at target spot
UINT8 ubTargetLevel = SpotDangerLevel(pSoldier, sGridNo, fCheckWater, fCheckLight);
// avoid moving into dangerous spot
if (ubTargetLevel > 0 && ubTargetLevel >= ubLevel)
return FALSE;
return TRUE;
}
+17 -104
View File
@@ -1499,19 +1499,7 @@ INT32 FindSpotMaxDistFromOpponents(SOLDIERTYPE *pSoldier)
continue;
}
//Madd: skip lighted spots
if ( InLightAtNight( sGridNo, pSoldier->pathing.bLevel ) )
continue;
// sevenfm: avoid staying at north edge
if (!gGameExternalOptions.fAITacticalRetreat &&
NorthSpot(sGridNo, pSoldier->pathing.bLevel))
{
continue;
}
// sevenfm: avoid red smoke
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, TRUE))
{
continue;
}
@@ -1665,38 +1653,7 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
continue;
}
// sevenfm: check for gas
if (InGas(pSoldier, sGridNo))
{
continue;
}
// check for deep water
if (DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
{
continue;
}
// check for bombs nearby
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
{
continue;
}
// check for red smoke
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) > 0)
{
continue;
}
// sevenfm: avoid staying at north edge
if (NorthSpot(sGridNo, pSoldier->pathing.bLevel))
{
continue;
}
// check for red smoke
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) > 0)
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, FALSE))
{
continue;
}
@@ -1839,18 +1796,12 @@ INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
continue;
}
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, TRUE))
{
continue;
}
// sevenfm: avoid staying at north edge
if (NorthSpot(sGridNo, pSoldier->pathing.bLevel))
{
continue;
}
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel))
{
continue;
}
@@ -2026,24 +1977,7 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem )
continue;
}
// exclude locations with tear/mustard gas (at this point, smoke is cool!)
if (InGas(pSoldier, sGridNo))
{
continue;
}
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
{
continue;
}
// sevenfm: avoid staying at north edge
/*if (NorthSpot(sGridNo, pSoldier->pathing.bLevel))
{
continue;
}*/
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, FALSE))
{
continue;
}
@@ -2775,16 +2709,6 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
continue;
}
// exclude locations with tear/mustard gas (at this point, smoke is cool!)
if ( InGas( pSoldier, sGridNo ) )
{
continue;
}
//Madd: skip lighted spots
if ( InLightAtNight( sGridNo, pSoldier->pathing.bLevel ) )
continue;
// sevenfm: skip tiles too close to edge
if ( PythSpacesAway( FindNearestEdgePoint ( sGridNo ), sGridNo ) <= 2 )
{
@@ -2806,8 +2730,13 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
continue;
}
// sevenfm: avoid staying at north edge
if (NorthSpot(sGridNo, pSoldier->pathing.bLevel))
// avoid fresh corpses
if (GetNearestRottingCorpseAIWarning(sGridNo) > 0)
{
continue;
}
if (!CheckNPCDestination(pSoldier, sGridNo, FALSE, TRUE))
{
continue;
}
@@ -2823,20 +2752,16 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
continue;
}
// sevenfm: penalize locations near fresh corpses
if( GetNearestRottingCorpseAIWarning( sGridNo ) > 0 )
// sevenfm: penalize locations too far from noise gridno
if (PythSpacesAway(sGridNo, sPos) > MAX_FLANK_DIST_RED)
{
sTempDist = sTempDist / 2;
}
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
{
continue;
}
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
// sevenfm: try to flank closer to vision distance limit for faster flanking
if (PythSpacesAway(sGridNo, sPos) > sDistanceVisible + 10)
{
continue;
sTempDist = sTempDist / 2;
}
// sevenfm: penalize locations with no sight cover from noise gridno (supposed that we are sneaking)
@@ -2847,18 +2772,6 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
sTempDist = sTempDist / 2;
}
// sevenfm: penalize locations too far from noise gridno
if( PythSpacesAway( sGridNo, sPos) > MAX_FLANK_DIST_RED )
{
sTempDist = sTempDist / 2;
}
// sevenfm: try to flank closer to vision distance limit for faster flanking
if( PythSpacesAway( sGridNo, sPos) > sDistanceVisible + 10 )
{
sTempDist = sTempDist / 2;
}
// allow extra directions for flanking
if ( bAction == AI_ACTION_FLANK_LEFT )
{
+6
View File
@@ -296,17 +296,23 @@ INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier);
BOOLEAN ProneSightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
BOOLEAN SightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
BOOLEAN CheckDoorAtGridno(UINT32 usGridNo);
BOOLEAN CheckDoorNearGridno(UINT32 usGridNo);
BOOLEAN FindBombNearby( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDistance );
UINT8 RedSmokeDanger(INT32 sGridNo, INT8 bLevel);
BOOLEAN CheckArtilleryStrike(void);
BOOLEAN CheckRoof(INT32 sGridNo);
UINT8 TerrainDensity(INT32 sSpot, INT8 bLevel, UINT8 ubDistance, BOOLEAN fGrass);
BOOLEAN FindNearbyExplosiveStructure(INT32 sSpot, INT8 bLevel);
INT16 DistanceToClosestActiveOpponent(SOLDIERTYPE *pSoldier, INT32 sSpot);
BOOLEAN ValidOpponent(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pOpponent);
BOOLEAN AnyCoverFromSpot( INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThreatLevel );
UINT8 CountSeenEnemiesLastTurn( SOLDIERTYPE *pSoldier );
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight);
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight);
BOOLEAN NorthSpot(INT32 sSpot, INT8 bLevel);
BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier);
+53
View File
@@ -1478,6 +1478,59 @@ BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex )
return( FALSE );
}
BOOLEAN FindStruct(INT32 sSpot, INT8 bLevel, UINT16 usIndex)
{
if (TileIsOutOfBounds(sSpot))
return FALSE;
LEVELNODE *pStruct = NULL;
LEVELNODE *pOldStruct = NULL;
if (bLevel == 0)
{
pStruct = gpWorldLevelData[sSpot].pStructHead;
}
else
{
pStruct = gpWorldLevelData[sSpot].pOnRoofHead;
}
// Look through all structs
while (pStruct != NULL)
{
if (pStruct->usIndex == usIndex)
{
return(TRUE);
}
pOldStruct = pStruct;
pStruct = pStruct->pNext;
}
return FALSE;
}
BOOLEAN FindStructFlag(INT32 sSpot, INT8 bLevel, UINT32 uiFlag)
{
if (bLevel > 0)
return FALSE;
if (TileIsOutOfBounds(sSpot))
return FALSE;
STRUCTURE * pStructure;
pStructure = FindStructure(sSpot, uiFlag);
if (pStructure)
{
return TRUE;
}
return FALSE;
}
// same as RemoveStruct(...), except that this focuses on .pOnRoofHead instead of .pStructHead
BOOLEAN RemoveOnRoofStruct( INT32 iMapIndex, UINT16 usIndex )
{
+4
View File
@@ -170,4 +170,8 @@ void SetTreeTopStateForMap();
BOOLEAN IsOknoLevel( INT32 sGridNo );
BOOLEAN IsLegionLevel( INT32 sGridNo );
// sevenfm
BOOLEAN FindStruct(INT32 sSpot, INT8 bLevel, UINT16 usIndex);
BOOLEAN FindStructFlag(INT32 sSpot, INT8 bLevel, UINT32 uiFlag);
#endif