mirror of
https://github.com/1dot13/source.git
synced 2026-07-29 13:52:17 +02:00
-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:
@@ -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
@@ -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
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "Isometric Utils.h"
|
||||
#endif
|
||||
|
||||
#define ATTACK_VALUE_MULTIPLIER_FOR_SMOKE_GRENADES 0.5
|
||||
|
||||
extern INT16 DirIncrementer[8];
|
||||
|
||||
//
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user