-updated AI to use some features from Ja2CW

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@184 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
MaddMugsy
2006-06-07 03:48:02 +00:00
parent d9dc88cc3c
commit 75d9e1b1c7
7 changed files with 982 additions and 116 deletions
+31 -1
View File
@@ -8,6 +8,7 @@
extern BOOLEAN gfTurnBasedAI;
#define MAX_DIST 160
// THIS IS AN ITEM # - AND FOR NOW JUST COMPLETELY FAKE...
#define MAX_TOSS_SEARCH_DIST 1 // must throw within this of opponent
@@ -87,7 +88,7 @@ enum
#define PERCENT_TO_IGNORE_THREAT 50 // any less, use threat value
#define ACTION_TIMEOUT_CYCLES 50 // # failed cycles through AI
#define MAX_THREAT_RANGE 400 // 30 tiles worth
#define MAX_THREAT_RANGE 4000 // 30 tiles worth
#define MIN_PERCENT_BETTER 5 // 5% improvement in cover is good
@@ -222,3 +223,32 @@ INT16 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier );
BOOLEAN ArmySeesOpponents( void );
void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN suppressionFire);
void AskForNoise( SOLDIERTYPE * pSoldier, INT16 *sNoiseGridno, UINT8 *ubNoiseVolume, INT8 *bNoiseLevel, INT8 bDist );
INT32 RangeToClosestOpponent( SOLDIERTYPE *pSoldier );
INT16 FindClimbGridNo( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 bMaxActionPoints );
//BOOLEAN IsTooFarFromFriends( SOLDIERTYPE *pSoldier );
INT16 FindBestCoverNearTheGridNo(SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubSearchRadius );
INT16 FindRoofBetweenGridNos( INT16 sFGridNo, INT16 sSGridNo );
INT8 FindDirectionForClimbing( INT16 sGridNo );
enum
{
TM_OUTOFRANGE = 0,
TM_HASFIRED,
TM_TRIED_TO_CLIMB,
TM_TRIED_TO_CLIMBDOWN,
TM_LAST_DEST_GRID,
TM_LOOKED_FOR_COVER,
// TM_LOOKFORROOF,
MAX_NUMBER_OF_TM
};
extern INT32 gpTurnMem[ MAX_NUMBER_OF_TM ];
UINT32 CountRatingOfTeamMatesDensity( SOLDIERTYPE * pSoldier, INT16 sGridNo, INT32 iDist );
UINT32 CountRatingOfOpponentsDensity( SOLDIERTYPE * pSoldier, INT16 sGridNo, INT32 iDist );
UINT8 NeedTimeToReadyGun_IfAlreadyReady( SOLDIERTYPE *pSoldier );
SOLDIERTYPE* FindFriendFarthestFromEnemies( SOLDIERTYPE * pSoldier );
+172 -32
View File
@@ -27,6 +27,8 @@
// InWaterOrGas - gas stuff
// RoamingRange - point patrol stuff
extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady );
UINT8 Urgency[NUM_STATUS_STATES][NUM_MORALE_STATES] =
{
{URGENCY_LOW, URGENCY_LOW, URGENCY_LOW, URGENCY_LOW, URGENCY_LOW}, // green
@@ -47,7 +49,7 @@ UINT16 MovementMode[LAST_MOVEMENT_ACTION + 1][NUM_URGENCY_STATES] =
{WALKING, WALKING, WALKING }, // AI_ACTION_POINT_PATROL,
{WALKING, RUNNING, RUNNING }, // AI_ACTION_LEAVE_WATER_GAS,
{WALKING, SWATTING, RUNNING }, // AI_ACTION_SEEK_NOISE,
{WALKING, RUNNING, RUNNING }, // AI_ACTION_SEEK_NOISE,
{RUNNING, RUNNING, RUNNING }, // AI_ACTION_ESCORTED_MOVE,
{WALKING, RUNNING, RUNNING }, // AI_ACTION_RUN_AWAY,
@@ -55,7 +57,7 @@ UINT16 MovementMode[LAST_MOVEMENT_ACTION + 1][NUM_URGENCY_STATES] =
{WALKING, WALKING, WALKING }, // AI_ACTION_APPROACH_MERC
{RUNNING, RUNNING, RUNNING }, // AI_ACTION_TRACK
{RUNNING, RUNNING, RUNNING }, // AI_ACTION_EAT
{WALKING, RUNNING, SWATTING}, // AI_ACTION_PICKUP_ITEM
{WALKING, RUNNING, RUNNING}, // AI_ACTION_PICKUP_ITEM
{WALKING, WALKING, WALKING}, // AI_ACTION_SCHEDULE_MOVE
{WALKING, WALKING, WALKING}, // AI_ACTION_WALK
@@ -380,19 +382,16 @@ void NewDest(SOLDIERTYPE *pSoldier, UINT16 usGridNo)
{
if ( pSoldier->bTeam == ENEMY_TEAM && pSoldier->bAlertStatus == STATUS_RED )
{
/* remove warning (jonathanl)
switch( pSoldier->bAction )
{
*/
/*
case AI_ACTION_MOVE_TO_CLIMB:
case AI_ACTION_RUN_AWAY:
pSoldier->usUIMovementMode = DetermineMovementMode( pSoldier, pSoldier->bAction );
fSet = TRUE;
break;*/
// remove warning pt2 (jonathanl)
// default:
if ( PreRandom( 5 - SoldierDifficultyLevel( pSoldier ) ) == 0 )
break;
default:
/* if ( PreRandom( 5 - SoldierDifficultyLevel( pSoldier ) ) == 0 )
{
INT16 sClosestNoise = (INT16) MostImportantNoiseHeard( pSoldier, NULL, NULL, NULL );
if ( sClosestNoise != NOWHERE && PythSpacesAway( pSoldier->sGridNo, sClosestNoise ) < MaxDistanceVisible() + 10 )
@@ -400,16 +399,14 @@ void NewDest(SOLDIERTYPE *pSoldier, UINT16 usGridNo)
pSoldier->usUIMovementMode = SWATTING;
fSet = TRUE;
}
}
}*/
if ( !fSet )
{
pSoldier->usUIMovementMode = DetermineMovementMode( pSoldier, pSoldier->bAction );
fSet = TRUE;
}
/* remove warning pt3 (jonathanl)
break;
}
*/
}
else
@@ -436,6 +433,8 @@ void NewDest(SOLDIERTYPE *pSoldier, UINT16 usGridNo)
BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier)
{
INT8 bMinPointsNeeded = 0;
INT8 bAPForStandUp = 0;
INT8 bAPToLookAtWall = ( FindDirectionForClimbing( pSoldier->sGridNo ) == pSoldier->bDirection ) ? 0 : 1;
//NumMessage("AffordableAction - Guy#",pSoldier->ubID);
@@ -527,11 +526,14 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier)
case AI_ACTION_CLIMB_ROOF:
if (pSoldier->bLevel == 0)
{
bMinPointsNeeded = AP_CLIMBROOF;
if( PTR_CROUCHED ) bAPForStandUp = 2;
if( PTR_PRONE ) bAPForStandUp = 4;
bMinPointsNeeded = AP_CLIMBROOF + bAPForStandUp + bAPToLookAtWall;
}
else
{
bMinPointsNeeded = AP_CLIMBOFFROOF;
if( !PTR_CROUCHED ) bAPForStandUp = 2;
bMinPointsNeeded = AP_CLIMBOFFROOF + bAPForStandUp + bAPToLookAtWall;
}
break;
@@ -1423,7 +1425,7 @@ INT16 EstimatePathCostToLocation( SOLDIERTYPE * pSoldier, INT16 sDestGridNo, INT
{
// different buildings!
// yes, pass in same gridno twice... want closest climb-down spot for building we are on!
sClimbGridNo = FindClosestClimbPointAvailableToAI( pSoldier, pSoldier->sGridNo, pSoldier->sGridNo, FALSE );
sClimbGridNo = FindClosestClimbPointAvailableToAI( pSoldier, sDestGridNo, pSoldier->sGridNo, FALSE );
if (sClimbGridNo == NOWHERE)
{
sPathCost = 0;
@@ -1464,7 +1466,7 @@ INT16 EstimatePathCostToLocation( SOLDIERTYPE * pSoldier, INT16 sDestGridNo, INT
else
{
// got to go DOWN off building
sClimbGridNo = FindClosestClimbPointAvailableToAI( pSoldier, pSoldier->sGridNo, pSoldier->sGridNo, FALSE );
sClimbGridNo = FindClosestClimbPointAvailableToAI( pSoldier, sDestGridNo, pSoldier->sGridNo, FALSE );
}
if (sClimbGridNo == NOWHERE)
@@ -2233,6 +2235,8 @@ INT32 CalcManThreatValue( SOLDIERTYPE *pEnemy, INT16 sMyGrid, UINT8 ubReduceForC
INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT16 * pusFromGridNo)
{
if( pSoldier->bBleeding > 0 )return MAX_ROAMING_RANGE;
if ( CREATURE_OR_BLOODCAT( pSoldier ) )
{
if ( pSoldier->bAlertStatus == STATUS_BLACK )
@@ -2512,30 +2516,166 @@ BOOLEAN ArmySeesOpponents( void )
return( FALSE );
}
#ifdef DEBUGDECISIONS
void AIPopMessage ( STR16 str )
void AskForNoise( SOLDIERTYPE * pSoldier, INT16 *sNoiseGridno, UINT8 *ubNoiseVolume, INT8 *bNoiseLevel, INT8 bDist )
{
DebugAI((STR)str);
UINT32 uiLoop;
SOLDIERTYPE *pFriend;
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
pFriend = MercSlots[ uiLoop ];
// it's me! Next merc
if( pFriend == pSoldier )
continue;
// if this merc is inactive, at base, on assignment, dead, unconscious
if (!pFriend || (pFriend->bLife < OKLIFE))
{
continue; // next merc
}
if ( pSoldier->bTeam != pFriend->bTeam )
{
continue; // next merc
}
if( pFriend->sNoiseGridno != NOWHERE && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, pFriend->sGridNo ) / 10 <= bDist )
{
*sNoiseGridno = pFriend->sNoiseGridno;
*ubNoiseVolume = pFriend->ubNoiseVolume;
*bNoiseLevel = pFriend->bNoiseLevel;
return;
}
}
}
void AIPopMessage ( const char* str )
INT32 RangeToClosestOpponent( SOLDIERTYPE *pSoldier )
{
STR tempstr;
sprintf((CHAR *) tempstr,"%s", str);
DebugAI(tempstr);
INT16 sClosestDisturbance;
//BOOLEAN fClimb;
sClosestDisturbance = ClosestKnownOpponent(pSoldier, 0, 0);
if( sClosestDisturbance != NOWHERE )
return GetRangeFromGridNoDiff( pSoldier->sGridNo, sClosestDisturbance );
else
return 128;
}
void AINumMessage(const char* str, INT32 num)
UINT8 NeedTimeToReadyGun_IfAlreadyReady( SOLDIERTYPE *pSoldier )
{
STR tempstr;
sprintf((CHAR *) tempstr,"%s %d", str, num);
DebugAI(tempstr);
UINT16 usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE );
if( usAnimState == INVALID_ANIMATION || GetAPsToReadyWeapon( pSoldier, usAnimState ) == 0 )
{
if( pSoldier->inv[HANDPOS].usItem != NOTHING && Item[pSoldier->inv[HANDPOS].usItem ].usItemClass == IC_GUN )
return Weapon[ Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex ].ubReadyTime;
}
return 0;
}
void AINameMessage(SOLDIERTYPE * pSoldier,const char* str,INT32 num)
UINT32 CountRatingOfTeamMatesDensity( SOLDIERTYPE * pSoldier, INT16 sGridNo, INT32 iDist )
{
STR tempstr;
sprintf((CHAR *) tempstr,"%d %s %d",pSoldier->name , str, num);
DebugAI( tempstr );
//UINT8 X, Y , ubWhoIsThere;
DOUBLE ddCount;
// INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown;
// INT16 iGridNo;
DOUBLE ddDistance;
UINT32 uiLoop;
SOLDIERTYPE *pFriend;
DOUBLE ddMaxDistance = iDist;
ddCount = 0;
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
pFriend = MercSlots[ uiLoop ];
// it's me! Next merc
if( pFriend == pSoldier )
continue;
// if this merc is inactive, at base, on assignment, dead, unconscious
if (!pFriend || (pFriend->bLife < OKLIFE))
{
continue; // next merc
}
// if this man is neutral / on the same side
if ( pSoldier->bSide != pFriend->bSide )
{
continue; // next merc
}
ddDistance = (INT32)(GetRangeInCellCoordsFromGridNoDiff( sGridNo, pFriend->sGridNo ) / 10);
if( ddDistance > ddMaxDistance)
ddDistance = ddMaxDistance;
// if( ddDistance )
// ddDistance = iDist + 1 - ddDistance;
ddCount += max( 0, ddMaxDistance - ddDistance );
}
return( ddCount );
}
UINT32 CountRatingOfOpponentsDensity( SOLDIERTYPE * pSoldier, INT16 sGridNo, INT32 iDist )
{
//UINT8 X, Y , ubWhoIsThere;
DOUBLE ddCount;
// INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown;
// INT16 iGridNo;
DOUBLE ddDistance;
UINT32 uiLoop;
SOLDIERTYPE *pOpponent;
DOUBLE ddMaxDistance = iDist;
ddCount = 0;
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
pOpponent = MercSlots[ uiLoop ];
// it's me! Next merc
if( pOpponent == pSoldier )
continue;
// if this merc is inactive, at base, on assignment, dead, unconscious
if (!pOpponent || (pOpponent->bLife < OKLIFE))
{
continue; // next merc
}
// if this man is neutral / on the same side
if ( CONSIDERED_NEUTRAL( pSoldier, pOpponent ) || (pSoldier->bSide == pOpponent->bSide))
{
continue; // next merc
}
ddDistance = (INT32)(GetRangeInCellCoordsFromGridNoDiff( sGridNo, pOpponent->sGridNo ) / 10);
if( ddDistance > ddMaxDistance)
ddDistance = ddMaxDistance;
// if( ddDistance )
// ddDistance = iDist + 1 - ddDistance;
ddCount += max( 0, ddMaxDistance - ddDistance );
}
return( ddCount );
}
#endif
+2
View File
@@ -16,6 +16,8 @@
#include "Isometric Utils.h"
#endif
#define ATTACK_VALUE_MULTIPLIER_FOR_SMOKE_GRENADES 0.5
extern INT16 DirIncrementer[8];
//
+2 -2
View File
@@ -766,7 +766,7 @@ INT8 CreatureDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
#ifdef DEBUGDECISIONS
STR16 tempstr;
sprintf((CHAR *)tempstr,"%s - SEEKING FRIEND at %d, MOVING to %d",
pSoldier->name,pSoldier->ubCaller,pSoldier->usActionData);
pSoldier->name,sClosestFriend,pSoldier->usActionData);
AIPopMessage(tempstr);
#endif
return(AI_ACTION_SEEK_FRIEND);
@@ -1350,7 +1350,7 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier )
sprintf((CHAR *) tempstr, "%d(%s) %s %d(%s) at gridno %d (%d APs aim)\n",
pSoldier->ubID,pSoldier->name,
(ubBestAttackAction == AI_ACTION_FIRE_GUN)?"SHOOTS":((ubBestAttackAction == AI_ACTION_TOSS_PROJECTILE)?"TOSSES AT":"STABS"),
BestAttack.ubOpponent, "Some Guy",
BestAttack.ubOpponent,ExtMen[BestAttack.ubOpponent].name,
BestAttack.sTarget,BestAttack.ubAimTime) ;
DebugAI( tempstr );
#endif
+441 -64
View File
@@ -23,9 +23,89 @@
// #include "Air Raid.h"
#endif
INT32 gpTurnMem[ MAX_NUMBER_OF_TM ];
extern BOOLEAN InternalIsValidStance( SOLDIERTYPE *pSoldier, INT8 bDirection, INT8 bNewStance );
extern BOOLEAN gfHiddenInterrupt;
extern BOOLEAN gfUseAlternateQueenPosition;
#define BONUS_FOR_THROW_CHANCE_TO_HIT ((INT32)50)
#define ADD_MAN_ON_ROOF_ON_EACH_N_SQUARE 1//18
#define MAX_DISTANCE_TO_ASK_NOISE 10
#define CHANCE_TO_STAY_ON_ROOF 95
#define MIN_RANGE_TO_ENEMY_TO_DO_SOMETHING 5
#define MIN_OVERALL_ROOF_BONUS 7
#define MIN_PENALTY_TO_ATTACK_ENEMY_ROOF 9
#define MAX_HIT_CHANCE_TO_ATTACK_ENEMY_ROOF 60
#define COST_OF_READY_AP 2
#define EXTRA_CHANCE_OF_BURST_IF_CAN_FIRE_WITH_SAME_AIM_TIME 50
static INT8 DecideActionOnClimbSpot( SOLDIERTYPE* pSoldier )
{
// INT8 bRightDir = FindDirectionForClimbing( pSoldier->sGridNo );
// INT8 bAPForLook = 0;
// INT8 bAPForStandUp = 0;
// if( pSoldier->bDirection != bRightDir ) bAPForLook = 1;
// if( PTR_CROUCHED ) bAPForStandUp = 2;
// if( PTR_PRONE ) bAPForStandUp = 4;
pSoldier->bAction = AI_ACTION_CLIMB_ROOF;
// pSoldier->bActionPoints -= bAPForStandUp + bAPForLook;
if( IsActionAffordable(pSoldier) )
{
// pSoldier->bActionPoints += bAPForStandUp + bAPForLook;
/// gpTurnMem[ TM_TRIED_TO_CLIMB ] = TRUE;
// if( bAPForStandUp == 4 )
// pSoldier->usActionData = ANIM_CROUCH;
// if( bAPForStandUp == 2 )
// pSoldier->usActionData = ANIM_STAND;
// if( bAPForStandUp )
// return AI_ACTION_CHANGE_STANCE;
/* if( bAPForLook )
{
pSoldier->usActionData = bRightDir;
return(AI_ACTION_CHANGE_FACING);
}*/
return AI_ACTION_CLIMB_ROOF;
}//else
// pSoldier->bActionPoints += bAPForStandUp + bAPForLook;
/* if( pSoldier->bActionPoints > 2 && PTR_STANDING && pSoldier->bDirection != bRightDir )
{
pSoldier->usActionData = bRightDir;
return(AI_ACTION_CHANGE_FACING);
}else
if( pSoldier->bActionPoints > 6 && PTR_CROUCHED && pSoldier->bDirection != bRightDir )
{
pSoldier->usActionData = bRightDir;
return(AI_ACTION_CHANGE_FACING);
}*/
if( pSoldier->bActionPoints > 1 && PTR_STANDING )
{
pSoldier->usActionData = ANIM_CROUCH;
return( AI_ACTION_CHANGE_STANCE );
}
if( pSoldier->bLevel && pSoldier->bActionPoints > 1 && PTR_CROUCHED )
{
pSoldier->usActionData = ANIM_PRONE;
return( AI_ACTION_CHANGE_STANCE );
}
return AI_ACTION_NONE;
}
// global status time counters to determine what takes the most time
@@ -36,6 +116,11 @@ UINT32 guiRedSeekTimeTotal = 0, guiRedHelpTimeTotal = 0, guiRedHideTimeTotal = 0
UINT32 guiRedSeekCounter = 0, guiRedHelpCounter = 0; guiRedHideCounter = 0;
#endif
// maximum strength bonus or penalty for chance tofire burst
#define BURST_MAX_STRENGTH_BONUS 25
#define BURST_BONUS_PER_AP 3
#define OUT_OF_RANGE_GET_CLOSE_BASE_CHANCE 50
#define CENTER_OF_RING 11237
#define MAX_FLANKS_RED 15
@@ -46,6 +131,10 @@ UINT32 guiRedSeekCounter = 0, guiRedHelpCounter = 0; guiRedHideCounter = 0;
#define MIN_FLANK_DIST_RED 10 * STRAIGHT_RATIO
#define MAX_FLANK_DIST_RED 40 * STRAIGHT_RATIO
extern UINT8 CountFriendWithoutATarger( SOLDIERTYPE * pSoldier );
extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady );
void DoneScheduleAction( SOLDIERTYPE * pSoldier )
{
@@ -675,6 +764,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP || pSoldier->bNeutral || (pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
BOOLEAN fCivilianOrMilitia = PTR_CIV_OR_MILITIA;
if( pSoldier->sNoiseGridno == NOWHERE )AskForNoise( pSoldier, &pSoldier->sNoiseGridno, &pSoldier->ubNoiseVolume, &pSoldier->bNoiseLevel, MAX_DISTANCE_TO_ASK_NOISE);
gubNPCPathCount = 0;
@@ -1227,6 +1317,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
STR16 tempstr;
#endif
if( pSoldier->sNoiseGridno == NOWHERE )AskForNoise( pSoldier, &pSoldier->sNoiseGridno, &pSoldier->ubNoiseVolume, &pSoldier->bNoiseLevel, MAX_DISTANCE_TO_ASK_NOISE);
if (fCivilian)
{
@@ -1290,9 +1381,11 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
{
// set base chance according to orders
if ((pSoldier->bOrders == STATIONARY) || (pSoldier->bOrders == ONGUARD))
iChance = 50;
iChance = 60;
else // all other orders
iChance = 25;
iChance = 35;
if(pSoldier->bOrders == SEEKENEMY)
iChance = -15;
if (pSoldier->bAttitude == DEFENSIVE)
iChance += 15;
@@ -1322,7 +1415,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
(gTacticalStatus.Team[pSoldier->bTeam].bMenInSector > 1) )
{
// base chance depends on how much new info we have to radio to the others
iChance = 5 * WhatIKnowThatPublicDont(pSoldier,FALSE); // use 5 * for YELLOW alert
iChance = 5 * 5 * WhatIKnowThatPublicDont(pSoldier,FALSE); // use 5 * for YELLOW alert
// if I actually know something they don't and I ain't swimming (deep water)
if (iChance && !DeepWater( pSoldier->sGridNo ))
@@ -1344,7 +1437,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
case RNDPTPATROL:
case POINTPATROL: break;
case FARPATROL: iChance += -10; break;
case SEEKENEMY: iChance += -20; break;
case SEEKENEMY: iChance += 40; break;
}
// modify base chance according to attitude
@@ -1717,7 +1810,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
if (!SkipCoverCheck ) // && gfTurnBasedAI) // only do in turnbased
{
// remember that noise value is negative, and closer to 0 => more important!
iChance = 25;
iChance = 55;
iSneaky = 30;
// set base chance according to orders
@@ -1774,7 +1867,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
////////////////////////////////////////////////////////////////////////////
// SWITCH TO GREEN: determine if soldier acts as if nothing at all was wrong
////////////////////////////////////////////////////////////////////////////
if ((INT16)PreRandom(100) < 50)
if ((INT16)PreRandom(100) < 1)
{
#ifdef RECORDNET
fprintf(NetDebugFile,"\tDecideActionYellow: guynum %d ignores noise, switching to GREEN AI...\n",pSoldier->ubID);
@@ -1826,6 +1919,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
{
INT32 iCoverPercentBetter;
INT8 bActionReturned;
INT32 iDummy;
INT16 iChance,sClosestOpponent,sClosestFriend;
@@ -1835,6 +1929,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
INT8 bSeekPts = 0, bHelpPts = 0, bHidePts = 0, bWatchPts = 0;
INT8 bHighestWatchLoc;
ATTACKTYPE BestThrow, BestShot;
INT16 sBestCover = NOWHERE;
#ifdef AI_TIMING_TEST
UINT32 uiStartTime, uiEndTime;
#endif
@@ -1846,6 +1942,23 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
(pSoldier->bNeutral && gTacticalStatus.fCivGroupHostile[pSoldier->ubCivilianGroup] == CIV_GROUP_NEUTRAL) ||
(pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
double ddRatingDiff = CountRatingOfOpponentsDensity( pSoldier, pSoldier->sGridNo, MAX_DIST )==0?CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ):(CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ) / CountRatingOfOpponentsDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ) );
if( !ddRatingDiff )ddRatingDiff = 0.000000001;
if( pSoldier->sNoiseGridno == NOWHERE )AskForNoise( pSoldier, &pSoldier->sNoiseGridno, &pSoldier->ubNoiseVolume, &pSoldier->bNoiseLevel, MAX_DISTANCE_TO_ASK_NOISE);
if( !gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition && (pSoldier->bActionPoints >= AP_RADIO) && !fCivilian )
{
return(AI_ACTION_RED_ALERT);
}
if( gfTurnBasedAI )
if( gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition )
{
RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam);
}
// if we have absolutely no action points, we can't do a thing under RED!
if (!pSoldier->bActionPoints)
{
@@ -1995,11 +2108,37 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
}
}
if (ubCanMove && RangeToClosestOpponent( pSoldier ) > MIN_RANGE_TO_ENEMY_TO_DO_SOMETHING &&
!CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, 10 ) &&
ddRatingDiff < 1 )
{
////////////////////////////////////////////////////////////////////////
// RUN AWAY TO A FRIEND FARTHEST FROM KNOWN THREATS
////////////////////////////////////////////////////////////////////////
SOLDIERTYPE* pFriend = FindFriendFarthestFromEnemies( pSoldier );
if( pFriend )
{
pSoldier->usActionData = GoAsFarAsPossibleTowards(pSoldier,pFriend->sGridNo,AI_ACTION_SEEK_OPPONENT);
if( pSoldier->usActionData != NOWHERE )
{
if( CountRatingOfOpponentsDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ) >= CountRatingOfOpponentsDensity( pSoldier, pSoldier->usActionData, MAX_DIST ) )
return(AI_ACTION_RUN_AWAY);
}
}
}
////////////////////////////////////////////////////////////////////////////
// WHEN IN THE LIGHT, GET OUT OF THERE!
////////////////////////////////////////////////////////////////////////////
if ( ubCanMove && InLightAtNight( pSoldier->sGridNo, pSoldier->bLevel ) && pSoldier->bOrders != STATIONARY )
if ( ubCanMove && InLightAtNight( pSoldier->sGridNo, pSoldier->bLevel ) && pSoldier->bOrders != STATIONARY
&& pSoldier->bActionPoints <= pSoldier->bInitialActionPoints / 2)// && pSoldier->bActionInProgress != AI_ACTION_MOVE_TO_CLIMB )
{
if( gfTurnBasedAI )
pSoldier->usActionData = FindBestNearbyCover(pSoldier,pSoldier->bAIMorale,&iCoverPercentBetter);
else
pSoldier->usActionData = FindNearbyDarkerSpot( pSoldier );
if ( pSoldier->usActionData != NOWHERE )
{
@@ -2367,7 +2506,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: calculate morale");
return(AI_ACTION_RUN_AWAY);
}
}
/*
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
////////////////////////////////////////////////////////////////////////////
@@ -2449,7 +2588,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
}
}
}
*/
if ( !TANK( pSoldier ) )
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: main red ai");
@@ -2570,8 +2709,8 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
// modify RED movement tendencies according to morale
switch (pSoldier->bAIMorale)
{
case MORALE_HOPELESS: bSeekPts = -99; bHelpPts = -99; bHidePts = +2; bWatchPts = -99; break;
case MORALE_WORRIED: bSeekPts += -2; bHelpPts += 0; bHidePts += +2; bWatchPts += 1; break;
case MORALE_HOPELESS: bSeekPts = -99; bHelpPts = -99; bHidePts = +1; bWatchPts = -99; break;
case MORALE_WORRIED: bSeekPts += -1; bHelpPts += 0; bHidePts += +1; bWatchPts += 1; break;
case MORALE_NORMAL: bSeekPts += 0; bHelpPts += 0; bHidePts += 0; bWatchPts += 0; break;
case MORALE_CONFIDENT: bSeekPts += +1; bHelpPts += 0; bHidePts += -1; bWatchPts += 0; break;
case MORALE_FEARLESS: bSeekPts += +1; bHelpPts += 0; bHidePts = -1; bWatchPts += 0; break;
@@ -2580,14 +2719,14 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
// modify tendencies according to orders
switch (pSoldier->bOrders)
{
case STATIONARY: bSeekPts += -1; bHelpPts += -1; bHidePts += +1; bWatchPts += +1; break;
case ONGUARD: bSeekPts += -1; bHelpPts += 0; bHidePts += +1; bWatchPts += +1; break;
case CLOSEPATROL: bSeekPts += 0; bHelpPts += 0; bHidePts += 0; bWatchPts += 0; break;
case RNDPTPATROL: bSeekPts += 0; bHelpPts += 0; bHidePts += 0; bWatchPts += 0; break;
case POINTPATROL: bSeekPts += 0; bHelpPts += 0; bHidePts += 0; bWatchPts += 0; break;
case FARPATROL: bSeekPts += 0; bHelpPts += 0; bHidePts += 0; bWatchPts += 0; break;
case STATIONARY: bSeekPts += -1; bHelpPts += +1; bHidePts += +1; bWatchPts += +1; break;
case ONGUARD: bSeekPts += -1; bHelpPts += +1; bHidePts += +1; bWatchPts += +1; break;
case CLOSEPATROL: bSeekPts += 0; bHelpPts += +1; bHidePts += 0; bWatchPts += 0; break;
case RNDPTPATROL: bSeekPts += 0; bHelpPts += +1; bHidePts += 0; bWatchPts += 0; break;
case POINTPATROL: bSeekPts += 0; bHelpPts += +1; bHidePts += 0; bWatchPts += 0; break;
case FARPATROL: bSeekPts += 0; bHelpPts += +1; bHidePts += 0; bWatchPts += 0; break;
case ONCALL: bSeekPts += 0; bHelpPts += +1; bHidePts += -1; bWatchPts += 0; break;
case SEEKENEMY: bSeekPts += +1; bHelpPts += 0; bHidePts += -1; bWatchPts += -1; break;
case SEEKENEMY: bSeekPts += +1; bHelpPts += +1; bHidePts += +1; bWatchPts += -1; break;
}
// modify tendencies according to attitude
@@ -2614,6 +2753,9 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
// don't search for cover
bHidePts = -99;
}
else
bHelpPts = -99;
// while one of the three main RED REACTIONS remains viable
while ((bSeekPts > -90) || (bHelpPts > -90) || (bHidePts > -90) )
@@ -2625,7 +2767,17 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
#ifdef AI_TIMING_TESTS
uiStartTime = GetJA2Clock();
#endif
// get the location of the closest reachable opponent
sClosestDisturbance = ClosestReachableDisturbance(pSoldier,ubUnconsciousOK, &fClimb);
if( sClosestDisturbance == NOWHERE )
{
INT32 iNV;
BOOLEAN fR;
sClosestDisturbance = MostImportantNoiseHeard( pSoldier, &iNV, &fClimb, &fR );
}
#ifdef AI_TIMING_TESTS
uiEndTime = GetJA2Clock();
guiRedSeekTimeTotal += (uiEndTime - uiStartTime);
@@ -2867,6 +3019,12 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
//////////////////////////////////////////////////////////////////////
pSoldier->usActionData = InternalGoAsFarAsPossibleTowards(pSoldier,sClosestFriend,AP_CROUCH, AI_ACTION_SEEK_OPPONENT,0);
if ( gfTurnBasedAI && pSoldier->usActionData != NOWHERE )
{
pSoldier->usActionData = FindBestCoverNearTheGridNo( pSoldier, pSoldier->usActionData, 5 );
pSoldier->usActionData = GoAsFarAsPossibleTowards(pSoldier,pSoldier->usActionData,AI_ACTION_SEEK_OPPONENT);
}
if (pSoldier->usActionData != NOWHERE)
{
#ifdef DEBUGDECISIONS
@@ -2972,9 +3130,20 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: couldn't hide");
}
}
/////////////////////////////////////////////////////////////////////////////
// GET TO BETTER COVER
/////////////////////////////////////////////////////////////////////////////
if ( ubCanMove && ( ClosestReachableDisturbance(pSoldier, TRUE, &fClimb) == NOWHERE) )
{
sBestCover = FindBestNearbyCover(pSoldier,pSoldier->bAIMorale,&iCoverPercentBetter);
if( sBestCover != NOWHERE)
{
pSoldier->usActionData = sBestCover;
return(AI_ACTION_TAKE_COVER);
}
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: nothing to do!");
////////////////////////////////////////////////////////////////////////////
// NOTHING USEFUL POSSIBLE! IF NPC IS CURRENTLY UNDER FIRE, TRY TO RUN AWAY
@@ -3273,12 +3442,13 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: radio red alert?");
// DO NOTHING: Not enough points left to move, so save them for next turn
////////////////////////////////////////////////////////////////////////////
#ifdef DEBUGDECISIONS
AINameMessage(pSoldier,"- DOES NOTHING (RED)",1000);
#endif
}
#ifdef DEBUGDECISIONS
AINameMessage(pSoldier,"- DOES NOTHING (RED)",1000);
#endif
pSoldier->usActionData = NOWHERE;
return(AI_ACTION_NONE);
pSoldier->usActionData = NOWHERE;
return(AI_ACTION_NONE);
}
INT8 DecideActionBlack(SOLDIERTYPE *pSoldier)
@@ -3305,14 +3475,33 @@ INT8 DecideActionBlack(SOLDIERTYPE *pSoldier)
UINT8 ubBurstAPs;
UINT8 ubOpponentDir;
INT16 sCheckGridNo;
INT16 sCGridNo;
INT8 bLevel;
// INT8 bIndex;
INT8 bRealActionPoints;
double ddRatingDiff = CountRatingOfOpponentsDensity( pSoldier, pSoldier->sGridNo, MAX_DIST )==0?CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ):(CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ) / CountRatingOfOpponentsDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ) );
BOOLEAN fAllowCoverCheck = FALSE;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideActionBlack");
if( !ddRatingDiff )ddRatingDiff = 0.000000001;
if( gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition )
{
RadioSightings(pSoldier,EVERYBODY,pSoldier->bTeam);
}
if( !gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition )
if( (pSoldier->bActionPoints >= AP_RADIO) && !fCivilian )
{
return(AI_ACTION_RED_ALERT);
}
// once we hit status black, reset flanking status
//pSoldier->numFlanks = 0;
if( pSoldier->sNoiseGridno == NOWHERE )AskForNoise( pSoldier, &pSoldier->sNoiseGridno, &pSoldier->ubNoiseVolume, &pSoldier->bNoiseLevel, MAX_DISTANCE_TO_ASK_NOISE);
// if we have absolutely no action points, we can't do a thing under BLACK!
if (!pSoldier->bActionPoints)
@@ -3967,6 +4156,153 @@ bCanAttack = FALSE;
}
if (ubCanMove && RangeToClosestOpponent( pSoldier ) > MIN_RANGE_TO_ENEMY_TO_DO_SOMETHING &&
!CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, 10 ) &&
ddRatingDiff < 1 )
{
////////////////////////////////////////////////////////////////////////
// RUN AWAY TO A FRIEND FARTHEST FROM KNOWN THREATS
////////////////////////////////////////////////////////////////////////
SOLDIERTYPE* pFriend = FindFriendFarthestFromEnemies( pSoldier );
if( pFriend )
{
pSoldier->usActionData = GoAsFarAsPossibleTowards(pSoldier,pFriend->sGridNo,AI_ACTION_SEEK_OPPONENT);
if( pSoldier->usActionData != NOWHERE )
{
if( CountRatingOfOpponentsDensity( pSoldier, pSoldier->sGridNo, MAX_DIST ) >= CountRatingOfOpponentsDensity( pSoldier, pSoldier->usActionData, MAX_DIST ) )
return(AI_ACTION_RUN_AWAY);
}
}
}
////////////////////////////////////////////////////////////////////////////
// IF THE TARGET IS OUT OF WEAPON RANGE
////////////////////////////////////////////////////////////////////////////
if( gpTurnMem[TM_LAST_DEST_GRID] && gpTurnMem[TM_OUTOFRANGE] )
{
if( gpTurnMem[TM_LAST_DEST_GRID] != pSoldier->sGridNo && ( !BestAttack.ubPossible || BestAttack.ubChanceToReallyHit < 80 ) )
{
pSoldier->usActionData = GoAsFarAsPossibleTowards(pSoldier,gpTurnMem[TM_LAST_DEST_GRID],AI_ACTION_SEEK_OPPONENT);
if( pSoldier->usActionData != NOWHERE )
return AI_ACTION_GET_CLOSER;
}
}
else
if( ubCanMove && ubBestAttackAction == AI_ACTION_FIRE_GUN
&& Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN
&& RangeToClosestOpponent( pSoldier ) > MIN_RANGE_TO_ENEMY_TO_DO_SOMETHING
&& pSoldier->bActionPoints > 5 + NeedTimeToReadyGun_IfAlreadyReady( pSoldier )
&& BestAttack.ubChanceToReallyHit < 90 )
{
WEAPONTYPE WeapBuf = Weapon[ Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex ];
int iDistance = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, BestAttack.sTarget );
// ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld %ld %ld %ld", pSoldier->ubID, iDistance, BestAttack.ubChanceToReallyHit, ddRatingDiff / 10);
if( ( iDistance > WeapBuf.usRange && BestAttack.ubChanceToReallyHit < min( 90, 70 * ddRatingDiff ) ) ||
( BestAttack.ubChanceToReallyHit < min( 70, 30 * ddRatingDiff ) ) )
{
sClosestDisturbance = ClosestKnownOpponent( pSoldier, 0, &bLevel );
iChance = OUT_OF_RANGE_GET_CLOSE_BASE_CHANCE * iDistance / WeapBuf.usRange + 100 - BestAttack.ubChanceToReallyHit;
switch (pSoldier->bAttitude)
{
case DEFENSIVE: iChance += -50; break;
case BRAVESOLO: iChance += -10; break;
case BRAVEAID: iChance += -5; break;
case CUNNINGSOLO: iChance += -40; break;
case CUNNINGAID: iChance += -30; break;
case AGGRESSIVE: iChance += -10; break;
case ATTACKSLAYONLY:iChance += 0; break;
}
iChance -= NeedTimeToReadyGun_IfAlreadyReady( pSoldier ) * COST_OF_READY_AP;
if( sClosestDisturbance != NOWHERE /*&& iChance > Random( 100 )*/ )
{
// try to move towards him
bRealActionPoints = pSoldier->bActionPoints;
if( iDistance <= WeapBuf.usRange )
pSoldier->bActionPoints = min( 4 + 2 * iDistance/10 * ( (30 - BestAttack.ubChanceToReallyHit) / 30.0 ), bRealActionPoints );
else
pSoldier->bActionPoints = min( 9 + (iDistance - WeapBuf.usRange) / 10, bRealActionPoints );
pSoldier->usActionData = GoAsFarAsPossibleTowards( pSoldier, sClosestDisturbance, AI_ACTION_SEEK_OPPONENT );
pSoldier->bActionPoints = bRealActionPoints;
if (pSoldier->usActionData != NOWHERE)
{
sCGridNo = FindClimbGridNo( pSoldier, pSoldier->usActionData, -1 );
if( sCGridNo == pSoldier->sGridNo )
return DecideActionOnClimbSpot( pSoldier );
if ( sCGridNo != NOWHERE &&
( !pSoldier->bLevel && !InARoom( pSoldier->sGridNo, NULL ) && !gpTurnMem[ TM_TRIED_TO_CLIMBDOWN ]/*|| CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, 5 ) > 5 */) )
{
gpTurnMem[ TM_OUTOFRANGE ] = TRUE;
gpTurnMem[ TM_TRIED_TO_CLIMBDOWN ] = TRUE;
pSoldier->usActionData = sCGridNo;
pSoldier->usUIMovementMode = RUNNING;
pSoldier->fUIMovementFast = TRUE;
return( AI_ACTION_MOVE_TO_CLIMB );
}else
{
pSoldier->usActionData = FindBestCoverNearTheGridNo( pSoldier, pSoldier->usActionData, 5 );
pSoldier->usActionData = GoAsFarAsPossibleTowards(pSoldier,pSoldier->usActionData,AI_ACTION_SEEK_OPPONENT);
/* if( iDistance <= WeapBuf.usRange )
switch(pSoldier->usAnimState)
{
case ANIM_PRONE:
pSoldier->usUIMovementMode = CRAWLING;
pSoldier->fUIMovementFast = FALSE;
break;
case ANIM_CROUCH:
pSoldier->usUIMovementMode = SWATTING;
pSoldier->fUIMovementFast = FALSE;
break;
case ANIM_STAND:
pSoldier->usUIMovementMode = RUNNING;
break;
}*/
gpTurnMem[TM_LAST_DEST_GRID] = pSoldier->usActionData;
gpTurnMem[ TM_OUTOFRANGE ] = TRUE;
return( AI_ACTION_GET_CLOSER );
}
}else if( ( pSoldier->usActionData = FindClimbGridNo( pSoldier, sClosestDisturbance, -1 ) ) != NOWHERE
&& ( !pSoldier->bLevel && !InARoom( pSoldier->sGridNo, NULL ) ) && !gpTurnMem[ TM_TRIED_TO_CLIMBDOWN ] )
{
if( pSoldier->usActionData == pSoldier->sGridNo )
return DecideActionOnClimbSpot( pSoldier );
gpTurnMem[ TM_OUTOFRANGE ] = TRUE;
gpTurnMem[ TM_TRIED_TO_CLIMBDOWN ] = TRUE;
pSoldier->usUIMovementMode = RUNNING;
pSoldier->fUIMovementFast = TRUE;
return( AI_ACTION_MOVE_TO_CLIMB );
}
}
}
}
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"LOOK FOR SOME KIND OF COVER BETTER THAN WHAT WE HAVE NOW");
////////////////////////////////////////////////////////////////////////////
// LOOK FOR SOME KIND OF COVER BETTER THAN WHAT WE HAVE NOW
@@ -3997,6 +4333,11 @@ bCanAttack = FALSE;
{
// gotta compare their merits and select the more desirable option
iOffense = BestAttack.ubChanceToReallyHit;
if( !gpTurnMem[ TM_LOOKED_FOR_COVER ] && BestAttack.ubChanceToReallyHit < 80 )
{
iDefense = 100 + iCoverPercentBetter;
gpTurnMem[ TM_LOOKED_FOR_COVER ] = TRUE;
}else
iDefense = iCoverPercentBetter;
// based on how we feel about the situation, decide whether to attack first
@@ -4037,12 +4378,12 @@ bCanAttack = FALSE;
switch (pSoldier->bAttitude)
{
case DEFENSIVE: iDefense += 30; break;
case BRAVESOLO: iDefense -= 0; break;
case BRAVEAID: iDefense -= 0; break;
case CUNNINGSOLO: iDefense += 20; break;
case CUNNINGAID: iDefense += 20; break;
case AGGRESSIVE: iOffense += 10; break;
case DEFENSIVE: iDefense += 20; break;
case BRAVESOLO: iDefense -= 10; break;
case BRAVEAID: iDefense -= 10; break;
case CUNNINGSOLO: iDefense += 10; break;
case CUNNINGAID: iDefense += 10; break;
case AGGRESSIVE: iOffense += 20; break;
case ATTACKSLAYONLY:iOffense += 30; break;
}
@@ -4363,7 +4704,7 @@ bCanAttack = FALSE;
DebugAI( tempstr);
#endif
gpTurnMem[ TM_HASFIRED ] =TRUE;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, String("DecideActionBlack: Check for GL Bursts, is launcher capable? = %d, rtpcombat? = %d, bestattackaction = %d",IsGunBurstCapable( pSoldier, BestAttack.bWeaponIn, FALSE ),pSoldier->bRTPCombat,ubBestAttackAction ));
if (ubBestAttackAction == AI_ACTION_TOSS_PROJECTILE && IsGunBurstCapable( pSoldier, BestAttack.bWeaponIn, FALSE ) &&
(pSoldier->bTeam != gbPlayerNum || pSoldier->bRTPCombat == RTP_COMBAT_AGGRESSIVE) )
@@ -4468,7 +4809,21 @@ bCanAttack = FALSE;
pSoldier->usActionData = sBestCover;
return(AI_ACTION_TAKE_COVER);
}
////////////////////////////////////////////////////////////////////////////
// PICKUP A NEARBY ITEM THAT'S USEFUL
////////////////////////////////////////////////////////////////////////////
if ( ubCanMove && !pSoldier->bNeutral && (gfTurnBasedAI || pSoldier->bTeam == ENEMY_TEAM ) )
{
pSoldier->bAction = SearchForItems( pSoldier, SEARCH_GENERAL_ITEMS, pSoldier->inv[HANDPOS].usItem );
if (pSoldier->bAction != AI_ACTION_NONE)
{
return( pSoldier->bAction );
}
}
////////////////////////////////////////////////////////////////////////////
@@ -4631,8 +4986,33 @@ bCanAttack = FALSE;
}
}
// if a militia has absofreaking nothing else to do, maybe they should radio in a report!
////////////////////////////////////////////////////////////////////////////
// CROUCH OR PRONE, IF THERE'S NOTHING TO DO ELSE
////////////////////////////////////////////////////////////////////////////
if( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND )
if( pSoldier->bActionPoints >= GetAPsToChangeStance( pSoldier, ANIM_CROUCH )
&& IsValidStance( pSoldier, ANIM_CROUCH ) )
{
pSoldier->usActionData = ANIM_CROUCH;
return(AI_ACTION_CHANGE_STANCE);
}
if( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH )
if( pSoldier->bActionPoints >= GetAPsToChangeStance( pSoldier, ANIM_PRONE )
&& IsValidStance( pSoldier, ANIM_PRONE ) )
{
sClosestOpponent = ClosestSeenOpponent(pSoldier, NULL, NULL);
if(sClosestOpponent == NOWHERE || GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sClosestOpponent ) / 10 > 10)
{
pSoldier->usActionData = ANIM_PRONE;
return(AI_ACTION_CHANGE_STANCE);
}
}
}
/*
// if a militia has absofreaking nothing else to do, maybe they should radio in a report!
////////////////////////////////////////////////////////////////////////////
// RADIO RED ALERT: determine %chance to call others and report contact
////////////////////////////////////////////////////////////////////////////
@@ -4642,10 +5022,8 @@ bCanAttack = FALSE;
// if there hasn't been an initial RED ALERT yet in this sector
if ( !(gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition) || NeedToRadioAboutPanicTrigger() )
{ // since I'm at STATUS RED, I obviously know we're being invaded!
DebugMsg(TOPIC_JA2AI,DBG_LEVEL_3,String("DecideActionBlack: check chance to radio contact"));
iChance = gbDiff[DIFF_RADIO_RED_ALERT][ SoldierDifficultyLevel( pSoldier ) ];
}
// since I'm at STATUS RED, I obviously know we're being invaded!
iChance = gbDiff[DIFF_RADIO_RED_ALERT][ SoldierDifficultyLevel( pSoldier ) ];
else // subsequent radioing (only to update enemy positions, request help)
// base chance depends on how much new info we have to radio to the others
iChance = 10 * WhatIKnowThatPublicDont(pSoldier,FALSE); // use 10 * for RED alert
@@ -4663,7 +5041,7 @@ bCanAttack = FALSE;
case RNDPTPATROL:
case POINTPATROL: iChance += -5; break;
case FARPATROL: iChance += -10; break;
case SEEKENEMY: iChance += -20; break;
case SEEKENEMY: iChance += 40; break;
}
// modify base chance according to attitude
@@ -4712,7 +5090,7 @@ bCanAttack = FALSE;
}
}
}
*/
////////////////////////////////////////////////////////////////////////////
// LEAVE THE SECTOR
////////////////////////////////////////////////////////////////////////////
@@ -4724,15 +5102,13 @@ bCanAttack = FALSE;
////////////////////////////////////////////////////////////////////////////
#ifdef DEBUGDECISIONS
AINameMessage(pSoldier,"- DOES NOTHING (BLACK)",1000);
AINameMessage(pSoldier,"- DOES NOTHING (BLACK)",1000);
#endif
// by default, if everything else fails, just stand in place and wait
pSoldier->usActionData = NOWHERE;
return(AI_ACTION_NONE);
// by default, if everything else fails, just stand in place and wait
pSoldier->usActionData = NOWHERE;
return(AI_ACTION_NONE);
}
INT8 DecideAction(SOLDIERTYPE *pSoldier)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideAction");
@@ -4849,14 +5225,14 @@ INT8 DecideAction(SOLDIERTYPE *pSoldier)
#ifdef DEBUGDECISIONS
sprintf((CHAR *) tempstr,"DecideAction: selected action %d, actionData %d\n\n",bAction,pSoldier->usActionData);
DebugAI((STR) tempstr );
#endif
#ifdef DEBUGDECISIONS
sprintf((CHAR *) tempstr,"DecideAction: selected action %d, actionData %d\n\n",bAction,pSoldier->usActionData);
DebugAI((STR) tempstr );
#endif
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideAction done");
return(bAction);
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideAction done");
return(bAction);
}
INT8 DecideActionEscort(SOLDIERTYPE *pSoldier)
@@ -4864,18 +5240,19 @@ INT8 DecideActionEscort(SOLDIERTYPE *pSoldier)
#ifdef DEBUGDECISIONS
STR16 tempstr;
#endif
// if he has a place to go, and isn't already there... go!
if (pSoldier->usActionData != NOWHERE && (pSoldier->sGridNo != pSoldier->usActionData))
{
#ifdef DEBUGDECISIONS
sprintf((CHAR *)tempstr,"%s - ESCORTED NPC GOING to grid %d",pSoldier->name,pSoldier->usActionData);
AIPopMessage(tempstr);
#endif
// if he has a place to go, and isn't already there... go!
if (pSoldier->usActionData != NOWHERE && (pSoldier->sGridNo != pSoldier->usActionData))
{
#ifdef DEBUGDECISIONS
sprintf((CHAR *)tempstr,"%s - ESCORTED NPC GOING to grid %d",pSoldier->name,pSoldier->usActionData);
AIPopMessage(tempstr);
#endif
return(AI_ACTION_ESCORTED_MOVE);
}
else
return(AI_ACTION_NONE);
return(AI_ACTION_ESCORTED_MOVE);
}
else
return(AI_ACTION_NONE);
}
+334 -7
View File
@@ -27,6 +27,9 @@
#include "PathAIDebug.h"
#define MINIMUM_DISTANCE_BETWEEN_TEAMMATES 10
#define MAX_NEAREST_ROOF_SEARCH_RADIUS 15
#ifdef _DEBUG
INT16 gsCoverValue[WORLD_MAX];
INT16 gsBestCover;
@@ -523,6 +526,8 @@ UINT8 NumberOfTeamMatesAdjacent( SOLDIERTYPE * pSoldier, INT16 sGridNo )
return( ubCount );
}
static INT16 gsDesiredGridNo = NOWHERE;
INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentBetter)
{
DebugMsg(TOPIC_JA2AI,DBG_LEVEL_3,String("FindBestNearbyCover"));
@@ -554,6 +559,7 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
UINT8 ubBackgroundLightPercent = 0;
UINT8 ubLightPercentDifference;
BOOLEAN fNight;
UINT16 usTmDistRatingBuffer;
switch( FindObj( pSoldier, GASMASK ) )
{
@@ -710,8 +716,14 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
iThreatCertainty = ThreatPercent[*pbPublOL - OLDEST_HEARD_VALUE];
}
sThreatLoc = pOpponent->sGridNo;
iThreatCertainty = 100;
// calculate how far away this threat is (in adjusted pixels)
//iThreatRange = AdjPixelsAway(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(sThreatLoc),CenterY(sThreatLoc));
if( gsDesiredGridNo != NOWHERE )
iThreatRange = GetRangeInCellCoordsFromGridNoDiff( gsDesiredGridNo, sThreatLoc );
else
iThreatRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sThreatLoc );
//NumMessage("Threat Range = ",iThreatRange);
@@ -721,7 +733,7 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
#endif
// if this opponent is believed to be too far away to really be a threat
if (iThreatRange > iMaxThreatRange)
if (iThreatRange > iMaxThreatRange + Weapon[ Item[pOpponent->inv[HANDPOS].usItem].ubClassIndex ].usRange + GetRangeBonus(&pOpponent->inv[HANDPOS]))
{
#ifdef DEBUGCOVER
// AINameMessage(pOpponent,"is too far away to be a threat",1000);
@@ -781,13 +793,51 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
if (Threat[uiLoop].iOrigRange <= MAX_THREAT_RANGE)
{
// add this opponent's cover value to our current total cover value
if( gsDesiredGridNo == NOWHERE )
iCurrentCoverValue += CalcCoverValue(pSoldier,pSoldier->sGridNo,iMyThreatValue,pSoldier->bActionPoints,uiLoop,Threat[uiLoop].iOrigRange,morale,&iCurrentScale);
else
iCurrentCoverValue += CalcCoverValue(pSoldier,gsDesiredGridNo,iMyThreatValue,pSoldier->bActionPoints,uiLoop,Threat[uiLoop].iOrigRange,morale,&iCurrentScale);
}
//sprintf((CHAR *)tempstr,"iCurrentCoverValue after opponent %d is now %d",iLoop,iCurrentCoverValue);
//PopMessage(tempstr);
}
iCurrentCoverValue -= (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
// iCurrentCoverValue -= (iCurrentCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, pSoldier->sGridNo );
if( gsDesiredGridNo == NOWHERE )
usTmDistRatingBuffer = CountRatingOfTeamMatesDensity( pSoldier, pSoldier->sGridNo, MINIMUM_DISTANCE_BETWEEN_TEAMMATES );
else
usTmDistRatingBuffer = CountRatingOfTeamMatesDensity( pSoldier, gsDesiredGridNo, MINIMUM_DISTANCE_BETWEEN_TEAMMATES );
usTmDistRatingBuffer *= usTmDistRatingBuffer;
// ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld:%ld", sGridNo, usTmDistRatingBuffer );
if ( iCurrentCoverValue >= 0 )
{
iCurrentCoverValue -= (iCurrentCoverValue / 10) * usTmDistRatingBuffer;
}
else
{
// when negative, must add a negative to decrease the total
iCurrentCoverValue += (iCurrentCoverValue / 10) * usTmDistRatingBuffer;
}
// It's better to be in a room...I guess...
if ( gsDesiredGridNo == NOWHERE ? InARoom( pSoldier->sGridNo, NULL ) : InARoom( gsDesiredGridNo, NULL ) )
{
if ( iCurrentCoverValue >= 0 )
{
iCurrentCoverValue += 2*iCurrentCoverValue;
}
else
{
iCurrentCoverValue -= 2*iCurrentCoverValue;
}
}
#ifdef DEBUGCOVER
// AINumMessage("Search Range = ",iSearchRange);
@@ -882,7 +932,11 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
//HandleMyMouseCursor(KEYBOARDALSO);
// calculate the next potential gridno
if( gsDesiredGridNo == NOWHERE )
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
else
sGridNo = gsDesiredGridNo + sXOffset + (MAXCOL * sYOffset);
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
{
continue;
@@ -929,6 +983,9 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
}
iPathCost = gubAIPathCosts[AI_PATHCOST_RADIUS + sXOffset][AI_PATHCOST_RADIUS + sYOffset];
if( iPathCost <= pSoldier->bActionPoints )iPathCost = 0;
/*
// water is OK, if the only good hiding place requires us to get wet, OK
iPathCost = LegalNPCDestination(pSoldier,sGridNo,ENSURE_PATH_COST,WATEROK);
@@ -975,14 +1032,25 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
// reduce cover for each person adjacent to this gridno who is on our team,
// by 10% (so locations next to several people will be very much frowned upon
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld", iCoverValue );
// if( !iCoverValue )
// iCoverValue -= 100;
usTmDistRatingBuffer = CountRatingOfTeamMatesDensity( pSoldier, sGridNo, MINIMUM_DISTANCE_BETWEEN_TEAMMATES );
usTmDistRatingBuffer *= usTmDistRatingBuffer;
// ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%ld:%ld", sGridNo, usTmDistRatingBuffer );
if ( iCoverValue >= 0 )
{
iCoverValue -= (iCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, sGridNo );
iCoverValue -= (iCoverValue / 10) * usTmDistRatingBuffer;
}
else
{
// when negative, must add a negative to decrease the total
iCoverValue += (iCoverValue / 10) * NumberOfTeamMatesAdjacent( pSoldier, sGridNo );
iCoverValue += (iCoverValue / 10) * usTmDistRatingBuffer;
}
if ( fNight && !( InARoom( sGridNo, NULL ) ) ) // ignore in buildings in case placed there
@@ -993,15 +1061,31 @@ INT16 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
ubLightPercentDifference = (gbLightSighting[ 0 ][ LightTrueLevel( sGridNo, pSoldier->bLevel ) ] - ubBackgroundLightPercent );
if ( iCoverValue >= 0 )
{
iCoverValue -= (iCoverValue / 100) * ubLightPercentDifference;
iCoverValue -= (iCoverValue / 20) * ubLightPercentDifference;
}
else
{
iCoverValue += (iCoverValue / 100) * ubLightPercentDifference;
iCoverValue += (iCoverValue / 20) * ubLightPercentDifference;
}
}
// It's better to be in a room...I guess...
if ( InARoom( sGridNo, NULL ) )
{
if ( iCoverValue >= 0 )
{
iCoverValue += 2*iCoverValue;
}
else
{
iCoverValue -= 2*iCoverValue;
}
}
#ifdef DEBUGCOVER
// if there ARE multiple opponents
if (uiThreatCnt > 1)
@@ -1616,7 +1700,7 @@ INT16 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
// CJC: here, unfortunately, we must calculate a path so we have an AP cost
sPathCost = LegalNPCDestination(pSoldier,sGridNo,ENSURE_PATH_COST,NOWATER,0);
sPathCost = LegalNPCDestination(pSoldier,sGridNo,ENSURE_PATH_COST,WATEROK,0);
if (!sPathCost)
{
@@ -2780,3 +2864,246 @@ BOOLEAN CanClimbFromHere (SOLDIERTYPE * pSoldier, BOOLEAN fUp )
return FALSE;
}
*/
extern BUILDING gBuildings[ MAX_BUILDINGS ];
extern UINT8 gubNumberOfBuildings;
BOOLEAN IsItValidClimbSpot( INT16 sGridNo, INT8 bLevel )
{
UINT16 usBuildingID;
UINT16 usClimbSpotIndex;
for( usBuildingID = 1; usBuildingID <= gubNumberOfBuildings ; ++usBuildingID )
for( usClimbSpotIndex = 0; usClimbSpotIndex < gBuildings[ usBuildingID ].ubNumClimbSpots ; ++usClimbSpotIndex )
if( gBuildings[ usBuildingID ].sUpClimbSpots[ usClimbSpotIndex ] == sGridNo && !bLevel )
{
if( WhoIsThere2( gBuildings[ usBuildingID ].sDownClimbSpots[ usClimbSpotIndex ], 1 ) == NOBODY )
return TRUE;
}else if( gBuildings[ usBuildingID ].sDownClimbSpots[ usClimbSpotIndex ] == sGridNo && bLevel )
{
if( WhoIsThere2( gBuildings[ usBuildingID ].sUpClimbSpots[ usClimbSpotIndex ], 0 ) == NOBODY )
return TRUE;
}
return FALSE;
}
BOOLEAN AreGridsAdjacent( INT16 sFGridNo, INT16 sSGridNo )
{
return sFGridNo == sSGridNo - 1 ||
sFGridNo == sSGridNo + 1 ||
sFGridNo == sSGridNo - MAXCOL ||
sFGridNo == sSGridNo + MAXCOL;
}
INT16 FindClimbGridNo( SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 bMaxActionPoints )
{
BOOLEAN fClimbingNecessary;
INT16 sCGridNo;
INT16 sActionPointsNeeded = EstimatePathCostToLocation( pSoldier, sGridNo, 1, FALSE, &fClimbingNecessary, &sCGridNo );
if( sActionPointsNeeded != 0 && fClimbingNecessary )
{
if( IsItValidClimbSpot( pSoldier->sGridNo, pSoldier->bLevel ) && AreGridsAdjacent( pSoldier->sGridNo, sCGridNo ) ) return pSoldier->sGridNo;
if( bMaxActionPoints < 0 || ( bMaxActionPoints >= 0 && sActionPointsNeeded <= bMaxActionPoints ) )
return sCGridNo;
else
return NOWHERE;
}
return NOWHERE;
}
INT16 FindBestCoverNearTheGridNo(SOLDIERTYPE *pSoldier, INT16 sGridNo, UINT8 ubSearchRadius )
{
INT32 iPercentBetter;
// INT16 sTrueGridNo;
INT16 sResultGridNo;
INT8 bRealWisdom = pSoldier->bWisdom;
// sTrueGridNo = pSoldier->sGridNo;
// pSoldier->sGridNo = sGridNo;
gsDesiredGridNo = sGridNo;
pSoldier->bWisdom = 8 * ubSearchRadius;// 5 tiles
sResultGridNo = FindBestNearbyCover( pSoldier, MORALE_NORMAL, &iPercentBetter);
pSoldier->bWisdom = bRealWisdom;
// pSoldier->sGridNo = sTrueGridNo;
gsDesiredGridNo = NOWHERE;
if( sResultGridNo != NOWHERE )
return sResultGridNo;
else
return sGridNo;
}
INT16 FindRoofBetweenGridNos( INT16 sFGridNo, INT16 sSGridNo )
{
INT16 sGridNo;
INT16 sCurrX, sCurrY;
INT16 sFGX, sFGY, sSGX, sSGY;
ConvertGridNoToXY( sFGridNo, &sFGX, &sFGY );
ConvertGridNoToXY( sSGridNo, &sSGX, &sSGY );
// if( pSoldier->bLevel )
// return NOWHERE;
// if ( gbWorldSectorZ > 0 )
// return NOWHERE;
if( sFGX == sSGX )
{
sCurrX = sFGX;
if( sFGY < sSGY )
for( sCurrY = sFGY; sCurrY < sSGY ; ++sCurrY )
{
sGridNo = sCurrX + (MAXCOL * sCurrY);
if( gubBuildingInfo[ sGridNo ] )
return sGridNo;
}else
if( sFGY > sSGY )
for( sCurrY = sFGY; sCurrY > sSGY ; --sCurrY )
{
sGridNo = sCurrX + (MAXCOL * sCurrY);
if( gubBuildingInfo[ sGridNo ] )
return sGridNo;
}
}else
if( sFGX < sSGX )
for( sCurrX = sFGX;sCurrX < sSGX ; ++sCurrX )
{
sCurrY = sFGY + ( sSGY - sFGY ) * ( (FLOAT)(sCurrX - sFGX) / (FLOAT)(sSGX - sFGX) );
sGridNo = sCurrX + (MAXCOL * sCurrY);
if( gubBuildingInfo[ sGridNo ] )
return sGridNo;
}else
if( sFGX > sSGX )
for( sCurrX = sFGX;sCurrX > sSGX ; --sCurrX )
{
sCurrY = sFGY + ( sSGY - sFGY ) * ( (FLOAT)(sCurrX - sFGX) / (FLOAT)(sSGX - sFGX) );
sGridNo = sCurrX + (MAXCOL * sCurrY);
if( gubBuildingInfo[ sGridNo ] )
return sGridNo;
}
return NOWHERE;
}
INT8 FindDirectionForClimbing( INT16 sGridNo )
{
UINT16 usBuildingID;
UINT16 usClimbSpotIndex;
for( usBuildingID = 0; usBuildingID < gubNumberOfBuildings ; ++usBuildingID )
for( usClimbSpotIndex = 0; usClimbSpotIndex < gBuildings[ usBuildingID ].ubNumClimbSpots ; ++usClimbSpotIndex )
if( gBuildings[ usBuildingID ].sUpClimbSpots[ usClimbSpotIndex ] == sGridNo )
{
if( WhoIsThere2( gBuildings[ usBuildingID ].sDownClimbSpots[ usClimbSpotIndex ], 1 ) == NOBODY )
return atan8(CenterX(sGridNo),CenterY(sGridNo),CenterX(gBuildings[ usBuildingID ].sDownClimbSpots[ usClimbSpotIndex ]),CenterY(gBuildings[ usBuildingID ].sDownClimbSpots[ usClimbSpotIndex ]));
}else if( gBuildings[ usBuildingID ].sDownClimbSpots[ usClimbSpotIndex ] == sGridNo )
{
if( WhoIsThere2( gBuildings[ usBuildingID ].sUpClimbSpots[ usClimbSpotIndex ], 0 ) == NOBODY )
return atan8(CenterX(sGridNo),CenterY(sGridNo),CenterX(gBuildings[ usBuildingID ].sUpClimbSpots[ usClimbSpotIndex ]),CenterY(gBuildings[ usBuildingID ].sUpClimbSpots[ usClimbSpotIndex ]));
}
return DIRECTION_IRRELEVANT;
}
SOLDIERTYPE* FindFriendFarthestFromEnemies( SOLDIERTYPE * pSoldier )
{
UINT32 uiLoop;
SOLDIERTYPE *pFriend;
SOLDIERTYPE *pBestFriend = 0;
UINT16 uiBestEnemyDensity = 0xFFFF;
UINT16 uiCurrEnemyDensity;
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
{
pFriend = MercSlots[ uiLoop ];
// it's me! Next merc
if( pFriend == pSoldier )
continue;
// if this merc is inactive, at base, on assignment, dead, unconscious
if (!pFriend || (pFriend->bLife < OKLIFE))
{
continue; // next merc
}
// if this man is neutral / on the same side
if ( pSoldier->bSide != pFriend->bSide )
{
continue; // next merc
}
uiCurrEnemyDensity = CountRatingOfOpponentsDensity( pFriend, pFriend->sGridNo, MAX_DIST );
if( uiCurrEnemyDensity < uiBestEnemyDensity )
{
uiBestEnemyDensity = uiCurrEnemyDensity;
pBestFriend = pFriend;
}
}
if( pBestFriend == pSoldier )
return 0;
return pBestFriend;
}
INT8 DetermineNearestRoof( SOLDIERTYPE *pSoldier )
{
INT32 iSearchRange;
INT16 sGridNo, sCGridNo, sBestCGridNo = NOWHERE;
INT8 sBestRoof = NO_BUILDING;
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
UINT8 ubBestDist = 255;
{
iSearchRange = MAX_NEAREST_ROOF_SEARCH_RADIUS;
// determine maximum horizontal limits
sMaxLeft = min(iSearchRange,(pSoldier->sGridNo % MAXCOL));
sMaxRight = min(iSearchRange,MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
// determine maximum vertical limits
sMaxUp = min(iSearchRange,(pSoldier->sGridNo / MAXROW));
sMaxDown = min(iSearchRange,MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
{
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
{
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
if( gubBuildingInfo[ sGridNo ] )
{
sCGridNo = FindClimbGridNo( pSoldier, sGridNo, -1 );
if( sCGridNo != NOWHERE && GetRangeFromGridNoDiff( pSoldier->sGridNo, sCGridNo ) < ubBestDist )
{
ubBestDist = GetRangeFromGridNoDiff( pSoldier->sGridNo, sCGridNo );
sBestCGridNo = sCGridNo;
sBestRoof = gubBuildingInfo[ sGridNo ];
}
}
}
}
if( sBestRoof )
return sBestRoof;
}
return NO_BUILDING;
}
-10
View File
@@ -239,16 +239,6 @@ BOOLEAN ValidCreatureTurn( SOLDIERTYPE * pCreature, INT8 bNewDirection );
BOOLEAN WearGasMaskIfAvailable( SOLDIERTYPE * pSoldier );
INT16 WhatIKnowThatPublicDont(SOLDIERTYPE *pSoldier, UINT8 ubInSightOnly);
#ifdef DEBUGDECISIONS
void AIPopMessage ( STR16 str );
void AIPopMessage ( const char* str );
void AINumMessage(const char* str, INT32 num);
void AINameMessage(SOLDIERTYPE * pSoldier,const char* str,INT32 num);
#endif
INT16 FindClosestClimbPoint (SOLDIERTYPE *pSoldier, BOOLEAN fClimbUp );
INT16 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT16 sPos, INT8 bAction );
BOOLEAN CanClimbFromHere (SOLDIERTYPE * pSoldier, BOOLEAN fUp );