mirror of
https://github.com/1dot13/source.git
synced 2026-09-02 14:36:06 +02:00
AI flanking improvement by Sevenfm:
Improved AI RED/YELLOW flanking: - better direction calculation (use direction arrays) - increased search range 4->8 - removed incorrectly calculated AP limit (use CalcActionPoints instead) - additional direction for flank spot searching - prefer desired direction - penalize tiles with no cover from noise location - penalize tiles too far from noise location - don't go into deep water for flanking - skip water tiles (can flank over water tiles only if can cross them in one turn) - min/max flanking range depends on time of day and base sight range - skip buildings when searching for flank spot if not in building already, because soldiers often run into buildings and stop flanking - use RUNNING movement mode for flanking instead of default SWATTING - only CUNNINGSOLO and CUNNINGAID soldiers flank - don't start flanking when no friends between soldier and noise gridno (in 3 directions) - stop flanking when no friends between soldier and noise gridno (in 3 directions) - stop flanking and reset flank counter in BLACK state - avoid map edges when flanking - disable flanking for soldiers with limited roaming range (STATIONARY/ONGUARD/CLOSEPATROL/SNIPER) In general, AI flanking is much more effective now (it never fully worked previously, especially in turnbased). git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8003 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
+45
-2
@@ -24,6 +24,7 @@
|
|||||||
#include "Soldier Create.h"
|
#include "Soldier Create.h"
|
||||||
#include "SkillCheck.h" // added by SANDRO
|
#include "SkillCheck.h" // added by SANDRO
|
||||||
#include "Vehicles.h" // added by silversurfer
|
#include "Vehicles.h" // added by silversurfer
|
||||||
|
#include "Game Clock.h" // added by sevenfm
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "GameInitOptionsScreen.h"
|
#include "GameInitOptionsScreen.h"
|
||||||
@@ -76,8 +77,8 @@ UINT16 MovementMode[LAST_MOVEMENT_ACTION + 1][NUM_URGENCY_STATES] =
|
|||||||
{WALKING, WALKING, WALKING}, // AI_ACTION_SCHEDULE_MOVE
|
{WALKING, WALKING, WALKING}, // AI_ACTION_SCHEDULE_MOVE
|
||||||
{WALKING, WALKING, WALKING}, // AI_ACTION_WALK
|
{WALKING, WALKING, WALKING}, // AI_ACTION_WALK
|
||||||
{WALKING, RUNNING, RUNNING}, // withdraw
|
{WALKING, RUNNING, RUNNING}, // withdraw
|
||||||
{WALKING, SWATTING, SWATTING}, // flank left
|
{RUNNING, RUNNING, SWATTING}, // flank left
|
||||||
{WALKING, SWATTING, SWATTING}, // flank right
|
{RUNNING, RUNNING, SWATTING}, // flank right
|
||||||
{RUNNING, RUNNING, RUNNING}, // AI_ACTION_MOVE_TO_CLIMB
|
{RUNNING, RUNNING, RUNNING}, // AI_ACTION_MOVE_TO_CLIMB
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3230,4 +3231,46 @@ UINT8 GetClosestMedicSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 auTe
|
|||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: define normal vision limits for day/night
|
||||||
|
INT16 MaxNormalVisionDistance( void )
|
||||||
|
{
|
||||||
|
if( NightTime() )
|
||||||
|
{
|
||||||
|
return gGameExternalOptions.ubStraightSightRange * STRAIGHT_RATIO;
|
||||||
|
}
|
||||||
|
return gGameExternalOptions.ubStraightSightRange * 2 * STRAIGHT_RATIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: check friendly soldiers between me and noise gridno
|
||||||
|
// count only friends that are active and not stationary/onguard/sniper
|
||||||
|
UINT8 CountFriendsInDirection( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
|
||||||
|
{
|
||||||
|
SOLDIERTYPE * pFriend;
|
||||||
|
UINT8 ubFriendDir, ubMyDir;
|
||||||
|
UINT8 ubFriends = 0;
|
||||||
|
|
||||||
|
ubMyDir = atan8(CenterX(sTargetGridNo),CenterY(sTargetGridNo),CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo));
|
||||||
|
|
||||||
|
// Run through each friendly.
|
||||||
|
for ( UINT8 iCounter = gTacticalStatus.Team[ pSoldier->bTeam ].bFirstID ; iCounter <= gTacticalStatus.Team[ pSoldier->bTeam ].bLastID ; iCounter ++ )
|
||||||
|
{
|
||||||
|
pFriend = MercPtrs[ iCounter ];
|
||||||
|
ubFriendDir = atan8(CenterX(sTargetGridNo),CenterY(sTargetGridNo),CenterX(pFriend->sGridNo),CenterY(pFriend->sGridNo));
|
||||||
|
|
||||||
|
if (pFriend != pSoldier &&
|
||||||
|
pFriend->bActive &&
|
||||||
|
pFriend->stats.bLife >= OKLIFE &&
|
||||||
|
pFriend->stats.bLife >= pFriend->stats.bLifeMax/2 &&
|
||||||
|
pFriend->aiData.bOrders > ONGUARD &&
|
||||||
|
pFriend->aiData.bOrders != SNIPER &&
|
||||||
|
(ubFriendDir == ubMyDir || ubFriendDir == gOneCDirection[ubMyDir] || ubFriendDir == gOneCCDirection[ubMyDir]) &&
|
||||||
|
PythSpacesAway( sTargetGridNo, pFriend->sGridNo) < PythSpacesAway(sTargetGridNo, pSoldier->sGridNo) )
|
||||||
|
{
|
||||||
|
ubFriends++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ubFriends;
|
||||||
}
|
}
|
||||||
+42
-14
@@ -57,14 +57,15 @@ UINT32 guiRedSeekCounter = 0, guiRedHelpCounter = 0; guiRedHideCounter = 0;
|
|||||||
|
|
||||||
#define CENTER_OF_RING 11237//dnl!!!
|
#define CENTER_OF_RING 11237//dnl!!!
|
||||||
|
|
||||||
#define MAX_FLANKS_RED 15
|
// sevenfm: moved to ai.h
|
||||||
|
/*#define MAX_FLANKS_RED 15
|
||||||
#define MAX_FLANKS_YELLOW 25
|
#define MAX_FLANKS_YELLOW 25
|
||||||
|
|
||||||
#define MIN_FLANK_DIST_YELLOW 10 * STRAIGHT_RATIO
|
#define MIN_FLANK_DIST_YELLOW 10 * STRAIGHT_RATIO
|
||||||
#define MAX_FLANK_DIST_YELLOW 50 * STRAIGHT_RATIO
|
#define MAX_FLANK_DIST_YELLOW 50 * STRAIGHT_RATIO
|
||||||
|
|
||||||
#define MIN_FLANK_DIST_RED 10 * STRAIGHT_RATIO
|
#define MIN_FLANK_DIST_RED 10 * STRAIGHT_RATIO
|
||||||
#define MAX_FLANK_DIST_RED 40 * STRAIGHT_RATIO
|
#define MAX_FLANK_DIST_RED 40 * STRAIGHT_RATIO*/
|
||||||
|
|
||||||
#ifdef ENABLE_ZOMBIES
|
#ifdef ENABLE_ZOMBIES
|
||||||
INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier);
|
INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier);
|
||||||
@@ -1928,7 +1929,9 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
|||||||
if ( origDir > currDir )
|
if ( origDir > currDir )
|
||||||
origDir -= NUM_WORLD_DIRECTIONS;
|
origDir -= NUM_WORLD_DIRECTIONS;
|
||||||
|
|
||||||
if ( (currDir - origDir) >= 4 )
|
// sevenfm: stop flanking if no friends between me and noise gridno
|
||||||
|
if ( (currDir - origDir) >= 4 ||
|
||||||
|
CountFriendsInDirection( pSoldier, tempGridNo ) == 0 )
|
||||||
{
|
{
|
||||||
pSoldier->numFlanks = MAX_FLANKS_YELLOW;
|
pSoldier->numFlanks = MAX_FLANKS_YELLOW;
|
||||||
}
|
}
|
||||||
@@ -1946,7 +1949,9 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
|||||||
if ( origDir < currDir )
|
if ( origDir < currDir )
|
||||||
origDir += NUM_WORLD_DIRECTIONS;
|
origDir += NUM_WORLD_DIRECTIONS;
|
||||||
|
|
||||||
if ( (origDir - currDir) >= 4 )
|
// sevenfm: stop flanking if no friends between me and noise gridno
|
||||||
|
if ( (origDir - currDir) >= 4 ||
|
||||||
|
CountFriendsInDirection( pSoldier, tempGridNo ) == 0 )
|
||||||
{
|
{
|
||||||
pSoldier->numFlanks = MAX_FLANKS_YELLOW;
|
pSoldier->numFlanks = MAX_FLANKS_YELLOW;
|
||||||
}
|
}
|
||||||
@@ -2090,7 +2095,14 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( pSoldier->aiData.bAttitude == CUNNINGAID || pSoldier->aiData.bAttitude == CUNNINGSOLO || pSoldier->aiData.bAttitude == BRAVESOLO ) )
|
// possibly start YELLOW flanking
|
||||||
|
// sevenfm: only CUNNINGAID and CUNNINGSOLO should flank
|
||||||
|
// check that there are some friends between me and noise gridno
|
||||||
|
// STATIONARY/ONGUARD/CLOSEPATROL/SNIPER should not flank
|
||||||
|
if ( ( pSoldier->aiData.bAttitude == CUNNINGAID || pSoldier->aiData.bAttitude == CUNNINGSOLO ) &&
|
||||||
|
CountFriendsInDirection( pSoldier, sNoiseGridNo ) > 0 &&
|
||||||
|
pSoldier->aiData.bOrders > CLOSEPATROL &&
|
||||||
|
pSoldier->aiData.bOrders != SNIPER )
|
||||||
{
|
{
|
||||||
INT8 action = AI_ACTION_SEEK_NOISE;
|
INT8 action = AI_ACTION_SEEK_NOISE;
|
||||||
INT16 dist = PythSpacesAway ( pSoldier->sGridNo, sNoiseGridNo );
|
INT16 dist = PythSpacesAway ( pSoldier->sGridNo, sNoiseGridNo );
|
||||||
@@ -3345,7 +3357,12 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
else
|
else
|
||||||
tempGridNo = sClosestDisturbance;
|
tempGridNo = sClosestDisturbance;
|
||||||
|
|
||||||
if ( pSoldier->numFlanks > 0 && pSoldier->numFlanks < MAX_FLANKS_RED && gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_PRONE )
|
// continue flanking
|
||||||
|
// sevenfm: dont' flank when under fire
|
||||||
|
if ( pSoldier->numFlanks > 0 &&
|
||||||
|
pSoldier->numFlanks < MAX_FLANKS_RED &&
|
||||||
|
gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_PRONE &&
|
||||||
|
!pSoldier->aiData.bUnderFire )
|
||||||
{
|
{
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: continue flanking");
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: continue flanking");
|
||||||
INT16 currDir = GetDirectionFromGridNo ( tempGridNo, pSoldier );
|
INT16 currDir = GetDirectionFromGridNo ( tempGridNo, pSoldier );
|
||||||
@@ -3356,7 +3373,9 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
if ( origDir > currDir )
|
if ( origDir > currDir )
|
||||||
origDir -= NUM_WORLD_DIRECTIONS;
|
origDir -= NUM_WORLD_DIRECTIONS;
|
||||||
|
|
||||||
if ( (currDir - origDir) >= 4 )
|
// sevenfm: stop flanking if no friend between me and noise gridno
|
||||||
|
if ( (currDir - origDir) >= 4 ||
|
||||||
|
CountFriendsInDirection( pSoldier, tempGridNo ) == 0 )
|
||||||
{
|
{
|
||||||
pSoldier->numFlanks = MAX_FLANKS_RED;
|
pSoldier->numFlanks = MAX_FLANKS_RED;
|
||||||
}
|
}
|
||||||
@@ -3375,7 +3394,9 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
if ( origDir < currDir )
|
if ( origDir < currDir )
|
||||||
origDir += NUM_WORLD_DIRECTIONS;
|
origDir += NUM_WORLD_DIRECTIONS;
|
||||||
|
|
||||||
if ( (origDir - currDir) >= 4 )
|
// sevenfm: stop flanking if no friend between me and noise gridno
|
||||||
|
if ( (origDir - currDir) >= 4 ||
|
||||||
|
CountFriendsInDirection( pSoldier, tempGridNo ) == 0 )
|
||||||
{
|
{
|
||||||
pSoldier->numFlanks = MAX_FLANKS_RED;
|
pSoldier->numFlanks = MAX_FLANKS_RED;
|
||||||
}
|
}
|
||||||
@@ -3592,8 +3613,15 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
// return( AI_ACTION_CLIMB_ROOF );
|
// return( AI_ACTION_CLIMB_ROOF );
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
// possibly start RED flanking
|
||||||
if ( ( pSoldier->aiData.bAttitude == CUNNINGAID || pSoldier->aiData.bAttitude == CUNNINGSOLO || pSoldier->aiData.bAttitude == BRAVESOLO ) && gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_PRONE )
|
// sevenfm: only CUNNINGAID and CUNNINGSOLO should flank
|
||||||
|
// check that there are friends between me and noise gridno
|
||||||
|
// STATIONARY\ONGUARD\CLOSEPATROL\SNIPER should not flank
|
||||||
|
if ( ( pSoldier->aiData.bAttitude == CUNNINGAID || pSoldier->aiData.bAttitude == CUNNINGSOLO ) &&
|
||||||
|
gAnimControl[ pSoldier->usAnimState ].ubHeight != ANIM_PRONE &&
|
||||||
|
CountFriendsInDirection( pSoldier, sClosestDisturbance ) > 0 &&
|
||||||
|
pSoldier->aiData.bOrders > CLOSEPATROL &&
|
||||||
|
pSoldier->aiData.bOrders != SNIPER )
|
||||||
{
|
{
|
||||||
INT8 action = AI_ACTION_SEEK_OPPONENT;
|
INT8 action = AI_ACTION_SEEK_OPPONENT;
|
||||||
INT16 dist = PythSpacesAway ( pSoldier->sGridNo, sClosestDisturbance );
|
INT16 dist = PythSpacesAway ( pSoldier->sGridNo, sClosestDisturbance );
|
||||||
@@ -4363,10 +4391,10 @@ INT16 ubMinAPCost;
|
|||||||
|
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack");
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack");
|
||||||
|
|
||||||
// once we hit status black, reset flanking status
|
// sevenfm: stop flanking when we see enemy
|
||||||
//pSoldier->numFlanks = 0;
|
if( pSoldier->numFlanks < MAX_FLANKS_RED )
|
||||||
|
pSoldier->numFlanks = 0;
|
||||||
|
|
||||||
// if we have absolutely no action points, we can't do a thing under BLACK!
|
// if we have absolutely no action points, we can't do a thing under BLACK!
|
||||||
if (!pSoldier->bActionPoints)
|
if (!pSoldier->bActionPoints)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2417,19 +2417,13 @@ INT32 FindNearestOpenableNonDoor( INT32 sStartGridNo )
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
||||||
{
|
{
|
||||||
INT32 sGridNo;
|
INT32 sGridNo;
|
||||||
INT32 sBestSpot = NOWHERE;
|
INT32 sBestSpot = NOWHERE;
|
||||||
INT32 iSearchRange = 4;
|
INT32 iSearchRange = 8; // sevenfm: increase search range
|
||||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||||
|
INT16 sDistanceVisible = MaxNormalVisionDistance();
|
||||||
|
|
||||||
DebugMsg ( TOPIC_JA2AI , DBG_LEVEL_3 , String("FindFlankingSpot: orig loc = %d, loc to flank = %d", pSoldier->sGridNo , sPos));
|
DebugMsg ( TOPIC_JA2AI , DBG_LEVEL_3 , String("FindFlankingSpot: orig loc = %d, loc to flank = %d", pSoldier->sGridNo , sPos));
|
||||||
|
|
||||||
@@ -2437,49 +2431,9 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
|||||||
if ( FindNearestEdgePoint ( pSoldier->sGridNo ) == pSoldier->sGridNo )
|
if ( FindNearestEdgePoint ( pSoldier->sGridNo ) == pSoldier->sGridNo )
|
||||||
return NOWHERE;
|
return NOWHERE;
|
||||||
|
|
||||||
|
// sevenfm: use max AP at the start of new turn
|
||||||
if ( gfTurnBasedAI )
|
//gubNPCAPBudget=(UINT8) (iSearchRange*3);
|
||||||
{
|
gubNPCAPBudget= pSoldier->CalcActionPoints();
|
||||||
//if (pSoldier->aiData.bAlertStatus == STATUS_BLACK) // if already in battle
|
|
||||||
//{
|
|
||||||
|
|
||||||
// iSearchRange = pSoldier->bActionPoints - ( MinAPsToAttack( pSoldier, sPos, ADDTURNCOST));
|
|
||||||
|
|
||||||
// // to speed this up, tell PathAI to cancel any paths beyond our AP reach!
|
|
||||||
// gubNPCAPBudget = iSearchRange; //pSoldier->bActionPoints;
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// // even if not under pressure, limit to 1 turn's travelling distance
|
|
||||||
// iSearchRange = pSoldier->bActionPoints - ( MinAPsToAttack( pSoldier, sPos, ADDTURNCOST));
|
|
||||||
|
|
||||||
// gubNPCAPBudget = iSearchRange; //__min( pSoldier->bActionPoints / 2, pSoldier->CalcActionPoints( ) );
|
|
||||||
|
|
||||||
//iSearchRange = gubNPCAPBudget;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if (!gfTurnBasedAI)
|
|
||||||
//{
|
|
||||||
// // search only half as far in realtime
|
|
||||||
// // but always allow a certain minimum!
|
|
||||||
|
|
||||||
// if ( iSearchRange > 20 )
|
|
||||||
// {
|
|
||||||
// iSearchRange /= 2;
|
|
||||||
// gubNPCAPBudget /= 2;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
gubNPCAPBudget=(UINT8) (iSearchRange*3);
|
|
||||||
|
|
||||||
// assume we have to stand up and turn
|
|
||||||
// use the min macro here to make sure we don't wrap the UINT8 to 255...
|
|
||||||
|
|
||||||
//gubNPCAPBudget = gubNPCAPBudget = __min( gubNPCAPBudget, gubNPCAPBudget - GetAPsToChangeStance( pSoldier, ANIM_STAND ) -1 ); //-1 for turning cost while standing
|
|
||||||
//NumMessage("Search Range = ",iSearchRange);
|
|
||||||
//NumMessage("gubNPCAPBudget = ",gubNPCAPBudget);
|
|
||||||
|
|
||||||
// stay away from the edges
|
|
||||||
|
|
||||||
// determine maximum horizontal limits
|
// determine maximum horizontal limits
|
||||||
sMaxLeft = min( iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
sMaxLeft = min( iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
||||||
@@ -2520,39 +2474,33 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
|||||||
// so we don't consider it
|
// so we don't consider it
|
||||||
gpWorldLevelData[pSoldier->sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
gpWorldLevelData[pSoldier->sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||||
|
|
||||||
|
|
||||||
// get direction of position to flank from soldier's position
|
// get direction of position to flank from soldier's position
|
||||||
INT16 sDir = GetDirectionFromGridNo ( sPos, pSoldier) ;
|
INT16 sDir = GetDirectionFromGridNo ( sPos, pSoldier) ;
|
||||||
INT16 sDesiredDir;
|
INT16 sDesiredDir;
|
||||||
INT16 sTempDir;
|
INT16 sTempDir;
|
||||||
INT16 sTempDist, sBestDist=0;
|
INT16 sTempDist, sBestDist=0;
|
||||||
|
|
||||||
|
// sevenfm: better direction calculation (use arrays)
|
||||||
switch ( bAction )
|
switch ( bAction )
|
||||||
{
|
{
|
||||||
case AI_ACTION_FLANK_LEFT:
|
case AI_ACTION_FLANK_LEFT:
|
||||||
sDesiredDir = sDir - 2;
|
sDesiredDir = gTwoCCDirection[ sDir ];
|
||||||
break;
|
break;
|
||||||
case AI_ACTION_FLANK_RIGHT:
|
case AI_ACTION_FLANK_RIGHT:
|
||||||
sDesiredDir = sDir + 2;
|
sDesiredDir = gTwoCDirection[ sDir ];
|
||||||
break;
|
break;
|
||||||
case AI_ACTION_WITHDRAW:
|
case AI_ACTION_WITHDRAW:
|
||||||
sDesiredDir = sDir + 4;
|
sDesiredDir = gOppositeDirection[ sDir ];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sDesiredDir = sDir;
|
sDesiredDir = sDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sDesiredDir < 0 )
|
|
||||||
sDesiredDir += NUM_WORLD_DIRECTIONS;
|
|
||||||
|
|
||||||
if ( sDesiredDir > NUM_WORLD_DIRECTIONS )
|
|
||||||
sDesiredDir -= NUM_WORLD_DIRECTIONS;
|
|
||||||
|
|
||||||
DebugMsg ( TOPIC_JA2AI , DBG_LEVEL_3 , String("FindFlankingSpot: direction to loc = %d, dir to flank = %d", sDir , sDesiredDir ));
|
DebugMsg ( TOPIC_JA2AI , DBG_LEVEL_3 , String("FindFlankingSpot: direction to loc = %d, dir to flank = %d", sDir , sDesiredDir ));
|
||||||
|
|
||||||
for (sYOffset = -sMaxUp + 1; sYOffset <= sMaxDown - 1; ++sYOffset)
|
for (sYOffset = -sMaxUp + 1; sYOffset <= sMaxDown - 1; sYOffset++)
|
||||||
{
|
{
|
||||||
for (sXOffset = -sMaxLeft + 1; sXOffset <= sMaxRight - 1; ++sXOffset)
|
for (sXOffset = -sMaxLeft + 1; sXOffset <= sMaxRight - 1; sXOffset++)
|
||||||
{
|
{
|
||||||
// calculate the next potential gridno
|
// calculate the next potential gridno
|
||||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||||
@@ -2585,20 +2533,66 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
|||||||
if ( InLightAtNight( sGridNo, pSoldier->pathing.bLevel ) )
|
if ( InLightAtNight( sGridNo, pSoldier->pathing.bLevel ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// allow an extra direction for flanking
|
// sevenfm: skip tiles too close to edge
|
||||||
|
if ( PythSpacesAway( FindNearestEdgePoint ( sGridNo ), sGridNo ) <= 2 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: don't go into deep water for flanking
|
||||||
|
if( DeepWater( sGridNo ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: skip water tiles
|
||||||
|
if( Water( sGridNo ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
//sTempDist = sTempDist/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: skip buildings if not in building already, because soldiers often run into buildings and stop flanking
|
||||||
|
if( InARoom( sGridNo, NULL ) && !InARoom(pSoldier->sGridNo, NULL) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: penalize locations with no sight cover from noise gridno (supposed that we are sneaking)
|
||||||
|
if( PythSpacesAway( sGridNo, sPos) < sDistanceVisible &&
|
||||||
|
LocationToLocationLineOfSightTest( sGridNo, pSoldier->pathing.bLevel, sPos, pSoldier->pathing.bLevel, TRUE) )
|
||||||
|
{
|
||||||
|
//continue;
|
||||||
|
sTempDist = sTempDist / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: penalize locations too far from noise gridno
|
||||||
|
if( PythSpacesAway( sGridNo, sPos) > MAX_FLANK_DIST_RED )
|
||||||
|
{
|
||||||
|
sTempDist = sTempDist / 2;
|
||||||
|
}
|
||||||
|
|
||||||
if ( bAction == AI_ACTION_FLANK_LEFT )
|
if ( bAction == AI_ACTION_FLANK_LEFT )
|
||||||
{
|
{
|
||||||
if ( sTempDir != sDesiredDir && sTempDir != ( sDesiredDir + 1 ) )
|
// sevenfm: allow two extra directions
|
||||||
|
if ( sTempDir != sDesiredDir && sTempDir != gOneCDirection[sDesiredDir] && sTempDir != gOneCCDirection[sDesiredDir])
|
||||||
continue;
|
continue;
|
||||||
|
// prefer desired dir x1.5
|
||||||
|
if( sTempDir == sDesiredDir )
|
||||||
|
sTempDist = 3*sTempDist/2;
|
||||||
}
|
}
|
||||||
else if ( bAction == AI_ACTION_FLANK_RIGHT )
|
else if ( bAction == AI_ACTION_FLANK_RIGHT )
|
||||||
{
|
{
|
||||||
if ( sTempDir != sDesiredDir && sTempDir != ( sDesiredDir - 1 ) )
|
// sevenfm: allow two extra directions
|
||||||
|
if ( sTempDir != sDesiredDir && sTempDir != gOneCDirection[sDesiredDir] && sTempDir != gOneCCDirection[sDesiredDir])
|
||||||
continue;
|
continue;
|
||||||
|
// prefer desired dir x1.5
|
||||||
|
if( sTempDir == sDesiredDir )
|
||||||
|
sTempDist = 3*sTempDist/2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( sTempDir != sDesiredDir ) //&& sTempDir != ( sDesiredDir + 1 ) && sTempDir != ( sDesiredDir - 1 ))
|
if ( sTempDir != sDesiredDir )
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2621,8 +2615,6 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
|||||||
return( sBestSpot );
|
return( sBestSpot );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INT32 FindClosestClimbPoint (SOLDIERTYPE *pSoldier, BOOLEAN fClimbUp )
|
INT32 FindClosestClimbPoint (SOLDIERTYPE *pSoldier, BOOLEAN fClimbUp )
|
||||||
{
|
{
|
||||||
INT32 sBestSpot = NOWHERE;
|
INT32 sBestSpot = NOWHERE;
|
||||||
|
|||||||
@@ -271,4 +271,27 @@ UINT8 GetClosestWoundedSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 au
|
|||||||
// get the id of the closest medic (closer than x tiles) of a specific team
|
// get the id of the closest medic (closer than x tiles) of a specific team
|
||||||
UINT8 GetClosestMedicSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 auTeam );
|
UINT8 GetClosestMedicSoldierID( SOLDIERTYPE * pSoldier, INT16 aRange, UINT8 auTeam );
|
||||||
|
|
||||||
|
// sevenfm:
|
||||||
|
|
||||||
|
INT16 MaxNormalVisionDistance( void );
|
||||||
|
UINT8 CountFriendsInDirection( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo );
|
||||||
|
BOOLEAN GuySawEnemyThisTurnOrBefore( SOLDIERTYPE * pSoldier );
|
||||||
|
|
||||||
|
// moved from DecideAction.cpp
|
||||||
|
// sevenfm: set MAX_FLANKS_RED and MAX_FLANKS_YELLOW to equal values to avoid problems when soldier's alert state changes
|
||||||
|
#define MAX_FLANKS_RED 25
|
||||||
|
#define MAX_FLANKS_YELLOW 25
|
||||||
|
|
||||||
|
// limit min/max flank distance depending on sight range and time of day
|
||||||
|
//#define MIN_FLANK_DIST_YELLOW 10 * STRAIGHT_RATIO
|
||||||
|
//#define MAX_FLANK_DIST_YELLOW 50 * STRAIGHT_RATIO
|
||||||
|
#define MIN_FLANK_DIST_YELLOW (2*MaxNormalVisionDistance()/3)
|
||||||
|
#define MAX_FLANK_DIST_YELLOW (MaxNormalVisionDistance() + 20)
|
||||||
|
|
||||||
|
// limit min/max flank distance depending on sight range and time of day
|
||||||
|
//#define MIN_FLANK_DIST_RED 10 * STRAIGHT_RATIO
|
||||||
|
//#define MAX_FLANK_DIST_RED 40 * STRAIGHT_RATIO
|
||||||
|
#define MIN_FLANK_DIST_RED (2*MaxNormalVisionDistance()/3)
|
||||||
|
#define MAX_FLANK_DIST_RED (MaxNormalVisionDistance() + 20)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user