Various AI improvements.

FindThrowableGrenade: allows to specify type and damage of searched grenade.
New counter SOLDIER_COUNTER_RETREAT allows to set number of turns which soldier will try to retreat and take cover.
FindBestNearbyCover: use PrepareThreatlist as unified function to make list of all known opponents.

Militia Control:
- start retreating mode for 2 turns when ordering retreat
- replace AI_ACTION_RUN_AWAY with AI_ACTION_TAKE_COVER order so that militia do not retreat from sector

New AI behavior:
- soldier can use smoke grenade to cover himself when under fire
- soldier can use use smoke grenade on his friend to cover him
- if soldier used smoke, he starts retreat mode for 2 turns
- added retreat code to Red, Black AI
- improved Main Red AI for civilians (they only run away)

Improved suppression code:
- less chance of suppression when opponent has high shock level
- prefer using suppression fire when soldier is in cover

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8879 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Sevenfm
2020-08-07 12:12:31 +00:00
parent 93c41f2f97
commit 5903abee09
14 changed files with 1359 additions and 292 deletions
+76 -18
View File
@@ -1870,48 +1870,106 @@ INT8 FindGLGrenade( SOLDIERTYPE * pSoldier )
return( NO_SLOT );
}
INT8 FindThrowableGrenade( SOLDIERTYPE * pSoldier )
INT8 FindThrowableGrenade(SOLDIERTYPE * pSoldier, UINT8 ubGrenadeType, UINT8 ubMinDamage)
{
INT8 bLoop;
BOOLEAN fCheckForFlares = FALSE;
UINT16 usItem;
INT8 invsize = (INT8)pSoldier->inv.size();
UINT8 ubDamage;
// JA2Gold: give some priority to looking for flares when at night
// this is AI only so we can put in some customization for night
if (GetTimeOfDayAmbientLightLevel() == NORMAL_LIGHTLEVEL_NIGHT)
// sevenfm: use flare only if cannot see opponent
if (NightLight() &&
pSoldier->aiData.bOppCnt == 0 &&
ubGrenadeType == EXPLOSV_ANY_TYPE &&
Chance(50))
{
if (pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 2))
{
fCheckForFlares = TRUE;
}
fCheckForFlares = TRUE;
}
INT8 invsize = (INT8)pSoldier->inv.size();
INT8 bFoundSlot = NO_SLOT;
UINT8 ubType;
UINT8 ubFoundType;
if (fCheckForFlares)
for (bLoop = 0; bLoop < invsize; ++bLoop)
{
// Do a priority check for flares first
for (bLoop = 0; bLoop < invsize; ++bLoop)
if (pSoldier->inv[bLoop].exists() == true)
{
if (pSoldier->inv[bLoop].exists() == true) {
if ( Item[pSoldier->inv[ bLoop ].usItem].flare )
usItem = pSoldier->inv[bLoop].usItem;
ubType = (UINT8)Explosive[Item[usItem].ubClassIndex].ubType;
ubDamage = Explosive[Item[usItem].ubClassIndex].ubDamage;
if ((Item[usItem].usItemClass & IC_GRENADE) &&
Item[usItem].ubCursor == TOSSCURS &&
GetLauncherFromLaunchable(usItem) == NOTHING &&
(!Item[usItem].flare || NightLight()) &&
ubDamage >= ubMinDamage &&
(ubGrenadeType == EXPLOSV_ANY_TYPE || ubType == ubGrenadeType))
{
// return if flare grenade has priority
if (fCheckForFlares && Item[usItem].flare)
{
return( bLoop );
return bLoop;
}
// return if found needed type
if (ubType == ubGrenadeType)
{
return bLoop;
}
// always prefer normal type
// smoke grenades have low priority
// mustard gas has priority over tear gas
if (bFoundSlot == NO_SLOT ||
ubType == EXPLOSV_NORMAL && ubFoundType != EXPLOSV_NORMAL ||
ubType != EXPLOSV_SMOKE && ubFoundType == EXPLOSV_SMOKE ||
ubType == EXPLOSV_MUSTGAS && ubFoundType == EXPLOSV_TEARGAS)
{
bFoundSlot = bLoop;
ubFoundType = ubType;
}
}
}
}
return(bFoundSlot);
}
UINT8 CountThrowableGrenades(SOLDIERTYPE * pSoldier, UINT8 ubGrenadeType, UINT8 ubMinDamage)
{
INT8 bLoop;
UINT16 usItem;
INT8 invsize = (INT8)pSoldier->inv.size();
UINT8 ubDamage;
INT8 bFoundSlot = NO_SLOT;
UINT8 ubType;
//UINT8 ubFoundType;
UINT8 ubCnt = 0;
for (bLoop = 0; bLoop < invsize; ++bLoop)
{
if (pSoldier->inv[bLoop].exists() == true) {
if ( (Item[ pSoldier->inv[ bLoop ].usItem ].usItemClass & IC_GRENADE) && // Try this check instead, to avoid tossing RPG rounds !GLGrenadeInSlot( pSoldier, bLoop ) &&
GetLauncherFromLaunchable( pSoldier->inv[ bLoop ].usItem) == NOTHING )
if (pSoldier->inv[bLoop].exists() == true)
{
usItem = pSoldier->inv[bLoop].usItem;
ubType = (UINT8)Explosive[Item[usItem].ubClassIndex].ubType;
ubDamage = Explosive[Item[usItem].ubClassIndex].ubDamage;
if ((Item[usItem].usItemClass & IC_GRENADE) &&
Item[usItem].ubCursor == TOSSCURS &&
GetLauncherFromLaunchable(usItem) == NOTHING &&
ubDamage >= ubMinDamage &&
(ubGrenadeType == EXPLOSV_ANY_TYPE || ubType == ubGrenadeType))
{
return( bLoop );
ubCnt++;
}
}
}
return( NO_SLOT );
return ubCnt;
}
INT16 FindAttachmentSlot( OBJECTTYPE* pObj, UINT16 usItem, UINT8 subObject)