Try to find a cover spot when advancing to attack

Calling InternalGoAsFarAsPossibleTowards() with target's gridno means AI doesn't take into account eg. nearby friendlies resulting in them bunching up and  making a beeline straight at whoever they're trying to attack.
We'll first at least attempt to find a cover spot near said target, if it doesn't work, only then head straight at them.
This commit is contained in:
Asdow
2024-02-10 18:35:45 +02:00
parent f6052f0eff
commit 93acd19c11
3 changed files with 39 additions and 23 deletions
+12 -1
View File
@@ -6697,7 +6697,18 @@ L_NEWAIM:
INT8 oldOrders = pSoldier->aiData.bOrders; INT8 oldOrders = pSoldier->aiData.bOrders;
pSoldier->aiData.sPatrolGrid[0] = pSoldier->sGridNo; pSoldier->aiData.sPatrolGrid[0] = pSoldier->sGridNo;
pSoldier->aiData.bOrders = CLOSEPATROL; pSoldier->aiData.bOrders = CLOSEPATROL;
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards( pSoldier, sClosestOpponent, BestAttack.ubAPCost, AI_ACTION_GET_CLOSER, 0 ); // Try to find a cover spot near opponent
iCoverPercentBetter = 0;
INT32 spotNearTarget = FindBestNearbyCover(pSoldier, pSoldier->aiData.bAIMorale, &iCoverPercentBetter, sClosestOpponent);
if (spotNearTarget != NOWHERE)
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, spotNearTarget, BestAttack.ubAPCost, AI_ACTION_GET_CLOSER, 0);
}
else
{
pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards( pSoldier, sClosestOpponent, BestAttack.ubAPCost, AI_ACTION_GET_CLOSER, 0 );
}
pSoldier->aiData.sPatrolGrid[0] = tgrd; pSoldier->aiData.sPatrolGrid[0] = tgrd;
pSoldier->aiData.bOrders = oldOrders; pSoldier->aiData.bOrders = oldOrders;
+26 -21
View File
@@ -612,7 +612,7 @@ UINT8 NumberOfTeamMatesAdjacent( SOLDIERTYPE * pSoldier, INT32 sGridNo )
return( ubCount ); return( ubCount );
} }
INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentBetter) INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentBetter, INT32 targetGridNo)
{ {
DebugMsg(TOPIC_JA2AI,DBG_LEVEL_3,String("FindBestNearbyCover")); DebugMsg(TOPIC_JA2AI,DBG_LEVEL_3,String("FindBestNearbyCover"));
@@ -649,6 +649,11 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
BOOLEAN fProneCover; BOOLEAN fProneCover;
UINT8 ubDiff = SoldierDifficultyLevel( pSoldier ); UINT8 ubDiff = SoldierDifficultyLevel( pSoldier );
if (targetGridNo == NOWHERE)
{
targetGridNo = pSoldier->sGridNo;
}
// There's no cover when boxing! // There's no cover when boxing!
if (gTacticalStatus.bBoxingState == BOXING) if (gTacticalStatus.bBoxingState == BOXING)
{ {
@@ -710,9 +715,9 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
}*/ }*/
// maximum search range is 1 tile / 8 pts of wisdom // maximum search range is 1 tile / 8 pts of wisdom
if (iSearchRange > (pSoldier->stats.bWisdom / 8)) if (iSearchRange > (pSoldier->stats.bWisdom / 4))
{ {
iSearchRange = (pSoldier->stats.bWisdom / 8); iSearchRange = (pSoldier->stats.bWisdom / 4);
} }
if (!gfTurnBasedAI) if (!gfTurnBasedAI)
@@ -777,13 +782,13 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
if (Threat[uiLoop].iOrigRange <= MAX_THREAT_RANGE) if (Threat[uiLoop].iOrigRange <= MAX_THREAT_RANGE)
{ {
// add this opponent's cover value to our current total cover value // add this opponent's cover value to our current total cover value
iCurrentCoverValue += CalcCoverValue(pSoldier,pSoldier->sGridNo,iMyThreatValue,pSoldier->bActionPoints,uiLoop,Threat[uiLoop].iOrigRange,morale,&iCurrentScale); iCurrentCoverValue += CalcCoverValue(pSoldier,targetGridNo,iMyThreatValue,pSoldier->bActionPoints,uiLoop,Threat[uiLoop].iOrigRange,morale,&iCurrentScale);
} }
// sevenfm: sight test // sevenfm: sight test
if( gGameExternalOptions.fAIBetterCover ) if( gGameExternalOptions.fAIBetterCover )
{ {
if ( LocationToLocationLineOfSightTest( Threat[uiLoop].sGridNo, Threat[uiLoop].pOpponent->pathing.bLevel, pSoldier->sGridNo, pSoldier->pathing.bLevel, TRUE, MAX_VISION_RANGE, STANDING_LOS_POS, PRONE_LOS_POS ) ) if ( LocationToLocationLineOfSightTest( Threat[uiLoop].sGridNo, Threat[uiLoop].pOpponent->pathing.bLevel, targetGridNo, pSoldier->pathing.bLevel, TRUE, MAX_VISION_RANGE, STANDING_LOS_POS, PRONE_LOS_POS ) )
//if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, pSoldier->sGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, NO_DISTANCE_LIMIT ) ) //if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, targetGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, NO_DISTANCE_LIMIT ) )
{ {
fProneCover = FALSE; fProneCover = FALSE;
} }
@@ -796,12 +801,12 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// by 10% (so locations next to several people will be very much frowned upon // by 10% (so locations next to several people will be very much frowned upon
if ( iCurrentCoverValue >= 0 ) if ( iCurrentCoverValue >= 0 )
{ {
iCurrentCoverValue -= (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo ); iCurrentCoverValue -= (iCurrentCoverValue / 5) * NumberOfTeamMatesAdjacent( pSoldier, targetGridNo );
} }
else else
{ {
// when negative, must add a negative to decrease the total // when negative, must add a negative to decrease the total
iCurrentCoverValue += (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo ); iCurrentCoverValue += (iCurrentCoverValue / 5) * NumberOfTeamMatesAdjacent( pSoldier, targetGridNo );
} }
if( gGameExternalOptions.fAIBetterCover ) if( gGameExternalOptions.fAIBetterCover )
@@ -816,17 +821,17 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
} }
// sevenfm: check for nearby friends, add bonus/penalty // sevenfm: check for nearby friends, add bonus/penalty
ubNearbyFriends = __min(5, CountNearbyFriends( pSoldier, pSoldier->sGridNo, 5 )); ubNearbyFriends = __min(5, CountNearbyFriends( pSoldier, targetGridNo, 5 ));
iCurrentCoverValue -= ubNearbyFriends * abs(iCurrentCoverValue) / (10-ubDiff); iCurrentCoverValue -= ubNearbyFriends * abs(iCurrentCoverValue) / (10-ubDiff);
// sevenfm: penalize locations with fresh corpses // sevenfm: penalize locations with fresh corpses
if(GetNearestRottingCorpseAIWarning( pSoldier->sGridNo ) > 0) if(GetNearestRottingCorpseAIWarning( targetGridNo ) > 0)
{ {
iCurrentCoverValue -= abs(iCurrentCoverValue) / (8-ubDiff); iCurrentCoverValue -= abs(iCurrentCoverValue) / (8-ubDiff);
} }
// sevenfm: penalize locations near red smoke // sevenfm: penalize locations near red smoke
iCurrentCoverValue -= abs(iCurrentCoverValue) * RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel) / 100; iCurrentCoverValue -= abs(iCurrentCoverValue) * RedSmokeDanger(targetGridNo, pSoldier->pathing.bLevel) / 100;
} }
#ifdef DEBUGCOVER #ifdef DEBUGCOVER
@@ -834,15 +839,15 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
#endif #endif
// determine maximum horizontal limits // determine maximum horizontal limits
sMaxLeft = min(iSearchRange,(pSoldier->sGridNo % MAXCOL)); sMaxLeft = min(iSearchRange,(targetGridNo % MAXCOL));
//NumMessage("sMaxLeft = ",sMaxLeft); //NumMessage("sMaxLeft = ",sMaxLeft);
sMaxRight = min(iSearchRange,MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1)); sMaxRight = min(iSearchRange,MAXCOL - ((targetGridNo % MAXCOL) + 1));
//NumMessage("sMaxRight = ",sMaxRight); //NumMessage("sMaxRight = ",sMaxRight);
// determine maximum vertical limits // determine maximum vertical limits
sMaxUp = min(iSearchRange,(pSoldier->sGridNo / MAXROW)); sMaxUp = min(iSearchRange,(targetGridNo / MAXROW));
//NumMessage("sMaxUp = ",sMaxUp); //NumMessage("sMaxUp = ",sMaxUp);
sMaxDown = min(iSearchRange,MAXROW - ((pSoldier->sGridNo / MAXROW) + 1)); sMaxDown = min(iSearchRange,MAXROW - ((targetGridNo / MAXROW) + 1));
//NumMessage("sMaxDown = ",sMaxDown); //NumMessage("sMaxDown = ",sMaxDown);
iRoamRange = RoamingRange(pSoldier,&sOrigin); iRoamRange = RoamingRange(pSoldier,&sOrigin);
@@ -852,7 +857,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
(!TileIsOutOfBounds(sOrigin))) (!TileIsOutOfBounds(sOrigin)))
{ {
// must try to stay within or return to the point of origin // must try to stay within or return to the point of origin
iDistFromOrigin = SpacesAway(sOrigin,pSoldier->sGridNo); iDistFromOrigin = SpacesAway(sOrigin,targetGridNo);
} }
else else
{ {
@@ -899,7 +904,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
{ {
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++) for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
{ {
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset); sGridNo = targetGridNo + sXOffset + (MAXCOL * sYOffset);
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) ) if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
{ {
continue; continue;
@@ -912,7 +917,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// Turn off the "reachable" flag for his current location // Turn off the "reachable" flag for his current location
// so we don't consider it // so we don't consider it
gpWorldLevelData[pSoldier->sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE); gpWorldLevelData[targetGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
// SET UP DOUBLE-LOOP TO STEP THROUGH POTENTIAL GRID #s // SET UP DOUBLE-LOOP TO STEP THROUGH POTENTIAL GRID #s
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++) for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
@@ -922,7 +927,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
//HandleMyMouseCursor(KEYBOARDALSO); //HandleMyMouseCursor(KEYBOARDALSO);
// calculate the next potential gridno // calculate the next potential gridno
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset); sGridNo = targetGridNo + sXOffset + (MAXCOL * sYOffset);
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) ) if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
{ {
continue; continue;
@@ -979,7 +984,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// sevenfm: avoid moving into light // sevenfm: avoid moving into light
if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) && if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) &&
!InLightAtNight(pSoldier->sGridNo, pSoldier->pathing.bLevel) && !InLightAtNight(targetGridNo, pSoldier->pathing.bLevel) &&
!pSoldier->aiData.bUnderFire) !pSoldier->aiData.bUnderFire)
{ {
continue; continue;
@@ -988,7 +993,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// avoid moving into red smoke // avoid moving into red smoke
if (gGameExternalOptions.fAIBetterCover && if (gGameExternalOptions.fAIBetterCover &&
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) && RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) &&
!RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)) !RedSmokeDanger(targetGridNo, pSoldier->pathing.bLevel))
{ {
//DebugCover(pSoldier, String("moving into red smoke, skip")); //DebugCover(pSoldier, String("moving into red smoke, skip"));
continue; continue;
+1 -1
View File
@@ -199,7 +199,7 @@ void EndAIGuysTurn( SOLDIERTYPE *pSoldier );
INT8 ExecuteAction(SOLDIERTYPE *pSoldier); INT8 ExecuteAction(SOLDIERTYPE *pSoldier);
INT32 FindAdjacentSpotBeside(SOLDIERTYPE *pSoldier, INT32 sGridNo); INT32 FindAdjacentSpotBeside(SOLDIERTYPE *pSoldier, INT32 sGridNo);
INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *pPercentBetter); INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *pPercentBetter, INT32 targetGridNo = NOWHERE);
INT32 FindClosestDoor( SOLDIERTYPE * pSoldier ); INT32 FindClosestDoor( SOLDIERTYPE * pSoldier );
INT32 FindNearbyPointOnEdgeOfMap( SOLDIERTYPE * pSoldier, INT8 * pbDirection ); INT32 FindNearbyPointOnEdgeOfMap( SOLDIERTYPE * pSoldier, INT8 * pbDirection );
INT32 FindNearestEdgePoint( INT32 sGridNo ); INT32 FindNearestEdgePoint( INT32 sGridNo );