AI improvements (by Sevenfm):

Bugfixes:
- Fix: Watched Locations system (never worked in 1.13)
- Fix: LineOfSight test with NO_DISTANCE_LIMIT (stopped on trees previously)

AI/tactical improvements:
- EstimateThrowDamage additionally calculates damage from fragments (important for AI to use frag grenades with low main damage and many fragments)
- EstimateThrowDamage correctly adds IndoorModifier
- Additional checks for RED suppression (check that the soldier will not shoot his friends, check that he has extra clip to reload weapon, check that target is not cowering, don't suppress when flanking)
- ClosestReachableDisturbance will use general noise only if cannot find any enemy
- Allow RED seeking in prone stance if we haven't seen enemy for several turns

Flanking improvements:
- allow YELLOW flanking for CLOSEPATROL at night
- better YELLOW/RED flanking start/stop conditions
- better RED AI behavior when finished flanking (try to reach flanking spot)
- allow RED flanking for CLOSEPATROL soldiers when at night, overcrowded or no other flanking soldiers yet

Optional AI improvements:
AI_EXTRA_SUPPRESSION
- AI will use suppression fire more often in RED state (set minimum AI CTH to 1)

AI_NEW_MORALE
- Better dynamic morale calculation depending on tactical situation.
- Additional min/max limits for AI morale
- Disabled HOPELESS morale for soldiers without guns (they can pick up weapon or attack with hands sometimes)

AI_BETTER_COVER
- Additional checks for line of sight, fresh corpses and overcrowded locations

AI_EXTRA_FLANKING
- Allow flanking for BRAVEAID/BRAVESOLO

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8006 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
silversurfer
2015-12-19 14:22:47 +00:00
parent 2c889635ac
commit dcf8b3abaf
12 changed files with 783 additions and 59 deletions
+84 -4
View File
@@ -29,6 +29,7 @@
#include "Buildings.h"
#include "GameSettings.h"
#include "Soldier Profile.h"
#include "rotting corpses.h" // sevenfm
#endif
@@ -567,6 +568,11 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
UINT8 ubLightPercentDifference;
BOOLEAN fNight;
// sevenfm
UINT8 ubNearbyFriends;
BOOLEAN fProneCover;
UINT8 ubDiff = SoldierDifficultyLevel( pSoldier );
// There's no cover when boxing!
if (gTacticalStatus.bBoxingState == BOXING)
{
@@ -628,7 +634,6 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
case AGGRESSIVE: iSearchRange -= 2; break;
}*/
// maximum search range is 1 tile / 8 pts of wisdom
if (iSearchRange > (pSoldier->stats.bWisdom / 8))
{
@@ -787,6 +792,9 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
iCurrentCoverValue = 0;
iCurrentScale = 0;
// sevenfm: sight cover
fProneCover = TRUE;
// for every opponent that threatens, consider this spot's cover vs. him
for (uiLoop = 0; uiLoop < uiThreatCnt; uiLoop++)
{
@@ -796,6 +804,14 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// 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);
}
// sevenfm: sight test
if( gGameExternalOptions.fAIBetterCover )
{
if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, pSoldier->sGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, -1 ) != 0 )
{
fProneCover = FALSE;
}
}
//sprintf(tempstr,"iCurrentCoverValue after opponent %d is now %d",iLoop,iCurrentCoverValue);
//PopMessage(tempstr);
}
@@ -812,6 +828,28 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
iCurrentCoverValue += (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
}
if( gGameExternalOptions.fAIBetterCover )
{
// sevenfm: when defending (range change <= 3), prefer locations with sight cover
if( RangeChangeDesire(pSoldier) < 4 )
{
if( fProneCover )
{
iCurrentCoverValue += abs(iCurrentCoverValue) / __max(2, 2*RangeChangeDesire(pSoldier));
}
}
// sevenfm: check for nearby friends, add bonus/penalty
ubNearbyFriends = __min(5, CountNearbyFriendlies( pSoldier, pSoldier->sGridNo, 5 ));
iCurrentCoverValue -= ubNearbyFriends * abs(iCurrentCoverValue) / (10-ubDiff);
// sevenfm: penalize locations with fresh corpses
if(GetNearestRottingCorpseAIWarning( pSoldier->sGridNo ) > 0)
{
iCurrentCoverValue -= abs(iCurrentCoverValue) / (8-ubDiff);
}
}
#ifdef DEBUGCOVER
// AINumMessage("Search Range = ",iSearchRange);
#endif
@@ -976,6 +1014,9 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
iCoverValue = 0;
iCoverScale = 0;
// sevenfm: check sight cover
fProneCover = TRUE;
// for every opponent that threatens, consider this spot's cover vs. him
for (uiLoop = 0; uiLoop < uiThreatCnt; uiLoop++)
{
@@ -989,6 +1030,15 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
uiLoop,iThreatRange,morale,&iCoverScale);
}
// sevenfm: sight test
if( gGameExternalOptions.fAIBetterCover )
{
if ( SoldierToVirtualSoldierLineOfSightTest( Threat[uiLoop].pOpponent, sGridNo, pSoldier->pathing.bLevel, ANIM_PRONE, TRUE, -1 ) != 0 )
{
fProneCover = FALSE;
}
}
//sprintf(tempstr,"iCoverValue after opponent %d is now %d",iLoop,iCoverValue);
//PopMessage(tempstr);
}
@@ -1005,6 +1055,26 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
iCoverValue += (iCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, sGridNo );
}
if( gGameExternalOptions.fAIBetterCover )
{
// sevenfm: when defending (range change <= 3), prefer locations with sight cover
if( RangeChangeDesire(pSoldier) < 4 )
{
if( fProneCover )
iCoverValue += abs(iCoverValue) / __max(2, 2*RangeChangeDesire(pSoldier));
}
// sevenfm: check for nearby friends in 10 radius, add bonus/penalty 10%
ubNearbyFriends = __min(5, CountNearbyFriendlies( pSoldier, sGridNo, 5 ));
iCoverValue -= ubNearbyFriends * abs(iCoverValue) / (10-ubDiff);
// sevenfm: penalize locations with fresh corpses
if(GetNearestRottingCorpseAIWarning( sGridNo ) > 0)
{
iCoverValue -= abs(iCoverValue) / (8-ubDiff);
}
}
if ( fNight && !( InARoom( sGridNo, NULL ) ) ) // ignore in buildings in case placed there
{
// reduce cover at nighttime based on how bright the light is at that location
@@ -2545,11 +2615,16 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
continue;
}
// sevenfm: skip water tiles
if( Water( sGridNo ) )
// sevenfm: allow water flanking only for CUNNINGSOLO soldiers
if( Water( sGridNo ) && pSoldier->aiData.bAttitude != CUNNINGSOLO )
{
continue;
//sTempDist = sTempDist/2;
}
// sevenfm: penalize locations near fresh corpses
if( GetNearestRottingCorpseAIWarning( sGridNo ) > 0 )
{
sTempDist = sTempDist / 2;
}
// sevenfm: skip buildings if not in building already, because soldiers often run into buildings and stop flanking
@@ -2571,6 +2646,11 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
{
sTempDist = sTempDist / 2;
}
// sevenfm: try to flank closer to vision distance limit for faster flanking
if( PythSpacesAway( sGridNo, sPos) > sDistanceVisible + 10 )
{
sTempDist = sTempDist / 2;
}
if ( bAction == AI_ACTION_FLANK_LEFT )
{