mirror of
https://github.com/1dot13/source.git
synced 2026-09-16 14:47:17 +02:00
AI pathing: avoid deep water if not in deep water already and not SEEKENEMY (allow max 2 tiles of deep water for other soldiers).
CONSIDERED_NEUTRAL: removed dying check as it may cause problems with AI. Improved code to avoid moving into gas/deep water/light/artillery danger zone. ClosestReachableDisturbance: - skip dying opponent if found not dying - when in deep water, skip opponents in deep water ClosestKnownOpponent: skip dying opponent if found not dying. RedSmokeDanger: consider deep water as safe from artillery strike. Allow deep water flanking for soldiers of ENEMY_TEAM with SEEKENEMY orders and CUNNINGSOLO attitude or athletics trait. CalcBestShot: - dying, cowering or unconscious soldiers have very low priority - added safety checks - if best opponent is dying and new opponent is ok, use new opponent DecideAction: improved deep water checks. Red, Black AI: when SEEKENEMY soldier is in deep water, move to closest opponent on the ground. FindNearestUngassedLand: - increased max search distance to 35 - added speed optimization - removed max AP budget FindNearbyDarkerSpot: - increased max search range to 25 - added speed optimization - removed max AP budget FindFlankingSpot: added condition to allow deep water flanking git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8758 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -93,7 +93,7 @@ namespace AI
|
|||||||
get_npc()->aiData.bAction = DecideActionYellow(get_npc());
|
get_npc()->aiData.bAction = DecideActionYellow(get_npc());
|
||||||
break;
|
break;
|
||||||
case STATUS_RED:
|
case STATUS_RED:
|
||||||
get_npc()->aiData.bAction = DecideActionRed(get_npc(),TRUE);
|
get_npc()->aiData.bAction = DecideActionRed(get_npc());
|
||||||
break;
|
break;
|
||||||
case STATUS_BLACK:
|
case STATUS_BLACK:
|
||||||
get_npc()->aiData.bAction = DecideActionBlack(get_npc());
|
get_npc()->aiData.bAction = DecideActionBlack(get_npc());
|
||||||
|
|||||||
+12
-1
@@ -3147,6 +3147,17 @@ if(!GridNoOnVisibleWorldTile(iDestination))
|
|||||||
goto NEXTDIR;
|
goto NEXTDIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sevenfm: skip deep water if not in deep water already
|
||||||
|
if (!(s->flags.uiStatusFlags & SOLDIER_PC) &&
|
||||||
|
s->ubProfile == NO_PROFILE &&
|
||||||
|
s->aiData.bOrders != SEEKENEMY &&
|
||||||
|
DeepWater(newLoc, bLevel) &&
|
||||||
|
!DeepWater(s->sGridNo, bLevel) &&
|
||||||
|
!FindNotDeepWaterNearby(newLoc, bLevel))
|
||||||
|
{
|
||||||
|
goto NEXTDIR;
|
||||||
|
}
|
||||||
|
|
||||||
// sevenfm: skip gas if not in gas already
|
// sevenfm: skip gas if not in gas already
|
||||||
if (!(s->flags.uiStatusFlags & SOLDIER_PC) &&
|
if (!(s->flags.uiStatusFlags & SOLDIER_PC) &&
|
||||||
InGasSpot(s, newLoc, bLevel) &&
|
InGasSpot(s, newLoc, bLevel) &&
|
||||||
@@ -3155,7 +3166,7 @@ if(!GridNoOnVisibleWorldTile(iDestination))
|
|||||||
goto NEXTDIR;
|
goto NEXTDIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WANNE: Know mines (for enemy or player) do not explode - BEGIN
|
// WANNE: Known mines (for enemy or player) do not explode - BEGIN
|
||||||
if ( gpWorldLevelData[newLoc].uiFlags & (MAPELEMENT_ENEMY_MINE_PRESENT | MAPELEMENT_PLAYER_MINE_PRESENT) )
|
if ( gpWorldLevelData[newLoc].uiFlags & (MAPELEMENT_ENEMY_MINE_PRESENT | MAPELEMENT_PLAYER_MINE_PRESENT) )
|
||||||
{
|
{
|
||||||
if (s->bSide == 0)
|
if (s->bSide == 0)
|
||||||
|
|||||||
@@ -660,9 +660,9 @@ extern CLOTHES_STRUCT Clothes[CLOTHES_MAX];
|
|||||||
// but they can't attack empty vehicles!!
|
// but they can't attack empty vehicles!!
|
||||||
// the_bob: also, creatures won't attack crows, because it seems to confuse the AI and cause freezes
|
// the_bob: also, creatures won't attack crows, because it seems to confuse the AI and cause freezes
|
||||||
#define CONSIDERED_NEUTRAL( me, them ) (\
|
#define CONSIDERED_NEUTRAL( me, them ) (\
|
||||||
( them->aiData.bNeutral || them->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER|SOLDIER_POW) || (them->flags.uiStatusFlags & SOLDIER_PC && them->stats.bLife < OKLIFE) ) \
|
(them->aiData.bNeutral || them->usSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER|SOLDIER_POW)) \
|
||||||
&& ( me->bTeam != CREATURE_TEAM || ( (them->flags.uiStatusFlags & SOLDIER_VEHICLE) || (them->ubBodyType == CROW) ) ) \
|
&& (me->bTeam != CREATURE_TEAM || (them->flags.uiStatusFlags & SOLDIER_VEHICLE) || (them->ubBodyType == CROW)) \
|
||||||
&& !( me->flags.uiStatusFlags & SOLDIER_BOXER && them->flags.uiStatusFlags & SOLDIER_BOXER ) \
|
&& !(me->flags.uiStatusFlags & SOLDIER_BOXER && them->flags.uiStatusFlags & SOLDIER_BOXER) \
|
||||||
)
|
)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ INT8 CanNPCAttack(SOLDIERTYPE *pSoldier);
|
|||||||
void CheckIfTossPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow);
|
void CheckIfTossPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow);
|
||||||
BOOLEAN ClimbingNecessary( SOLDIERTYPE * pSoldier, INT32 sDestGridNo, INT8 bDestLevel );
|
BOOLEAN ClimbingNecessary( SOLDIERTYPE * pSoldier, INT32 sDestGridNo, INT8 bDestLevel );
|
||||||
INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier );
|
INT8 ClosestPanicTrigger( SOLDIERTYPE * pSoldier );
|
||||||
INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK, BOOLEAN * pfChangeLevel );
|
INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, BOOLEAN * pfChangeLevel );
|
||||||
INT32 ClosestReachableFriendInTrouble(SOLDIERTYPE *pSoldier, BOOLEAN * pfClimbingNecessary);
|
INT32 ClosestReachableFriendInTrouble(SOLDIERTYPE *pSoldier, BOOLEAN * pfClimbingNecessary);
|
||||||
INT32 ClosestSeenOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
|
INT32 ClosestSeenOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLevel);
|
||||||
void CreatureCall( SOLDIERTYPE * pCaller );
|
void CreatureCall( SOLDIERTYPE * pCaller );
|
||||||
|
|||||||
+91
-47
@@ -950,7 +950,7 @@ INT16 RandomFriendWithin(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, usDest, TRUE, TRUE))
|
if (!CheckNPCDestination(pSoldier, usDest))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1115,7 +1115,7 @@ INT32 RandDestWithinRange(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, sRandDest, TRUE, TRUE))
|
if (!CheckNPCDestination(pSoldier, sRandDest))
|
||||||
{
|
{
|
||||||
sRandDest = NOWHERE;
|
sRandDest = NOWHERE;
|
||||||
continue;
|
continue;
|
||||||
@@ -1136,7 +1136,7 @@ INT32 RandDestWithinRange(SOLDIERTYPE *pSoldier)
|
|||||||
return(sRandDest); // defaults to NOWHERE
|
return(sRandDest); // defaults to NOWHERE
|
||||||
}
|
}
|
||||||
|
|
||||||
INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK, BOOLEAN * pfChangeLevel )
|
INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, BOOLEAN * pfChangeLevel )
|
||||||
{
|
{
|
||||||
INT32 *psLastLoc, *pusNoiseGridNo;
|
INT32 *psLastLoc, *pusNoiseGridNo;
|
||||||
INT8 *pbLastLevel;
|
INT8 *pbLastLevel;
|
||||||
@@ -1153,7 +1153,8 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
INT8 *pbNoiseLevel;
|
INT8 *pbNoiseLevel;
|
||||||
INT8 *pbPersOL,*pbPublOL;
|
INT8 *pbPersOL,*pbPublOL;
|
||||||
INT32 sClimbGridNo;
|
INT32 sClimbGridNo;
|
||||||
SOLDIERTYPE * pOpp;
|
SOLDIERTYPE *pOpponent;
|
||||||
|
SOLDIERTYPE *pClosestOpponent = NULL;
|
||||||
INT32 sDistToEnemy, sDistToClosestEnemy = 10000;
|
INT32 sDistToEnemy, sDistToClosestEnemy = 10000;
|
||||||
|
|
||||||
// sevenfm: safety check
|
// sevenfm: safety check
|
||||||
@@ -1174,30 +1175,30 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
// look through this man's personal & public opplists for opponents known
|
// look through this man's personal & public opplists for opponents known
|
||||||
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
||||||
{
|
{
|
||||||
pOpp = MercSlots[ uiLoop ];
|
pOpponent = MercSlots[ uiLoop ];
|
||||||
|
|
||||||
// if this merc is inactive, at base, on assignment, or dead
|
// if this merc is inactive, at base, on assignment, or dead
|
||||||
if (!pOpp)
|
if (!pOpponent)
|
||||||
{
|
{
|
||||||
continue; // next merc
|
continue; // next merc
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this merc is neutral/on same side, he's not an opponent
|
// if this merc is neutral/on same side, he's not an opponent
|
||||||
if ( CONSIDERED_NEUTRAL( pSoldier, pOpp ) || (pSoldier->bSide == pOpp->bSide) )
|
if ( CONSIDERED_NEUTRAL( pSoldier, pOpponent ) || (pSoldier->bSide == pOpponent->bSide) )
|
||||||
{
|
{
|
||||||
continue; // next merc
|
continue; // next merc
|
||||||
}
|
}
|
||||||
|
|
||||||
// silversurfer: ignore empty vehicles
|
// silversurfer: ignore empty vehicles
|
||||||
if ( pOpp->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle( pOpp->bVehicleID ) == 0 )
|
if ( pOpponent->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle( pOpponent->bVehicleID ) == 0 )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pbPersOL = pSoldier->aiData.bOppList + pOpp->ubID;
|
pbPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;
|
||||||
pbPublOL = gbPublicOpplist[pSoldier->bTeam] + pOpp->ubID;
|
pbPublOL = gbPublicOpplist[pSoldier->bTeam] + pOpponent->ubID;
|
||||||
psLastLoc = gsLastKnownOppLoc[pSoldier->ubID] + pOpp->ubID;
|
psLastLoc = gsLastKnownOppLoc[pSoldier->ubID] + pOpponent->ubID;
|
||||||
pbLastLevel = gbLastKnownOppLevel[pSoldier->ubID] + pOpp->ubID;
|
pbLastLevel = gbLastKnownOppLevel[pSoldier->ubID] + pOpponent->ubID;
|
||||||
|
|
||||||
// if this opponent is unknown personally and publicly
|
// if this opponent is unknown personally and publicly
|
||||||
if ((*pbPersOL == NOT_HEARD_OR_SEEN) && (*pbPublOL == NOT_HEARD_OR_SEEN))
|
if ((*pbPersOL == NOT_HEARD_OR_SEEN) && (*pbPublOL == NOT_HEARD_OR_SEEN))
|
||||||
@@ -1207,7 +1208,7 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
|
|
||||||
// this is possible if get here from BLACK AI in one of those rare
|
// this is possible if get here from BLACK AI in one of those rare
|
||||||
// instances when we couldn't get a meaningful shot off at a guy in sight
|
// instances when we couldn't get a meaningful shot off at a guy in sight
|
||||||
if ((*pbPersOL == SEEN_CURRENTLY) && (pOpp->stats.bLife >= OKLIFE))
|
if ((*pbPersOL == SEEN_CURRENTLY) && (pOpponent->stats.bLife >= OKLIFE))
|
||||||
{
|
{
|
||||||
// don't allow this to return any valid values, this guy remains a
|
// don't allow this to return any valid values, this guy remains a
|
||||||
// serious threat and the last thing we want to do is approach him!
|
// serious threat and the last thing we want to do is approach him!
|
||||||
@@ -1225,8 +1226,8 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// using public knowledge, obtain opponent's "best guess" gridno
|
// using public knowledge, obtain opponent's "best guess" gridno
|
||||||
sGridNo = gsPublicLastKnownOppLoc[pSoldier->bTeam][pOpp->ubID];
|
sGridNo = gsPublicLastKnownOppLoc[pSoldier->bTeam][pOpponent->ubID];
|
||||||
bLevel = gbPublicLastKnownOppLevel[pSoldier->bTeam][pOpp->ubID];
|
bLevel = gbPublicLastKnownOppLevel[pSoldier->bTeam][pOpponent->ubID];
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are standing at that gridno (!, obviously our info is old...)
|
// if we are standing at that gridno (!, obviously our info is old...)
|
||||||
@@ -1241,6 +1242,12 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sevenfm: when in deep water, skip opponents in deep water
|
||||||
|
if (DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel) && DeepWater(sGridNo, bLevel))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// sevenfm: if we found reachable enemy, check other enemies only if they are closer
|
// sevenfm: if we found reachable enemy, check other enemies only if they are closer
|
||||||
sDistToEnemy = PythSpacesAway( pSoldier->sGridNo, sGridNo );
|
sDistToEnemy = PythSpacesAway( pSoldier->sGridNo, sGridNo );
|
||||||
if (sDistToEnemy < sDistToClosestEnemy || TileIsOutOfBounds(sClosestDisturbance) )
|
if (sDistToEnemy < sDistToClosestEnemy || TileIsOutOfBounds(sClosestDisturbance) )
|
||||||
@@ -1248,7 +1255,10 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
iPathCost = EstimatePathCostToLocation( pSoldier, sGridNo, bLevel, FALSE, &fClimbingNecessary, &sClimbGridNo );
|
iPathCost = EstimatePathCostToLocation( pSoldier, sGridNo, bLevel, FALSE, &fClimbingNecessary, &sClimbGridNo );
|
||||||
|
|
||||||
// if we can get there and it's first reachable enemy or closer than other known enemies
|
// if we can get there and it's first reachable enemy or closer than other known enemies
|
||||||
if (iPathCost != 0 && (TileIsOutOfBounds(sClosestDisturbance) || iPathCost < iShortestPath))
|
if (iPathCost != 0 &&
|
||||||
|
(TileIsOutOfBounds(sClosestDisturbance) ||
|
||||||
|
iPathCost < iShortestPath ||
|
||||||
|
pClosestOpponent && !pClosestOpponent->IsZombie() && pClosestOpponent->stats.bLife < OKLIFE && pOpponent->stats.bLife >= OKLIFE))
|
||||||
{
|
{
|
||||||
if (fClimbingNecessary)
|
if (fClimbingNecessary)
|
||||||
{
|
{
|
||||||
@@ -1259,6 +1269,7 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
sClosestDisturbance = sGridNo;
|
sClosestDisturbance = sGridNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pClosestOpponent = pOpponent;
|
||||||
sDistToClosestEnemy = sDistToEnemy;
|
sDistToClosestEnemy = sDistToEnemy;
|
||||||
iShortestPath = iPathCost;
|
iShortestPath = iPathCost;
|
||||||
fClosestClimbingNecessary = fClimbingNecessary;
|
fClosestClimbingNecessary = fClimbingNecessary;
|
||||||
@@ -1278,11 +1289,11 @@ INT32 ClosestReachableDisturbance(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK,
|
|||||||
{
|
{
|
||||||
for(uiLoop=0; uiLoop<guiNumMercSlots; uiLoop++)//dnl ch58 160813
|
for(uiLoop=0; uiLoop<guiNumMercSlots; uiLoop++)//dnl ch58 160813
|
||||||
{
|
{
|
||||||
pOpp = MercSlots[uiLoop];
|
pOpponent = MercSlots[uiLoop];
|
||||||
if(pOpp && pSoldier->bSide == pOpp->bSide && pSoldier->ubID != pOpp->ubID&& pSoldier->aiData.sNoiseGridno == pOpp->aiData.sNoiseGridno)
|
if(pOpponent && pSoldier->bSide == pOpponent->bSide && pSoldier->ubID != pOpponent->ubID&& pSoldier->aiData.sNoiseGridno == pOpponent->aiData.sNoiseGridno)
|
||||||
{
|
{
|
||||||
pOpp->aiData.sNoiseGridno = NOWHERE;// Erase for all from the same team as it not useful anymore, this will avoid others to check already tested location
|
pOpponent->aiData.sNoiseGridno = NOWHERE;// Erase for all from the same team as it not useful anymore, this will avoid others to check already tested location
|
||||||
pOpp->aiData.ubNoiseVolume = 0;
|
pOpponent->aiData.ubNoiseVolume = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pSoldier->aiData.sNoiseGridno = NOWHERE; // wipe it out, not useful anymore
|
pSoldier->aiData.sNoiseGridno = NOWHERE; // wipe it out, not useful anymore
|
||||||
@@ -1379,11 +1390,11 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
|||||||
INT32 iRange, iClosestRange = 1500;
|
INT32 iRange, iClosestRange = 1500;
|
||||||
INT8 *pbPersOL,*pbPublOL;
|
INT8 *pbPersOL,*pbPublOL;
|
||||||
INT8 bLevel, bClosestLevel;
|
INT8 bLevel, bClosestLevel;
|
||||||
SOLDIERTYPE * pOpp;
|
SOLDIERTYPE *pOpponent;
|
||||||
|
SOLDIERTYPE *pClosestOpponent = NULL;
|
||||||
|
|
||||||
bClosestLevel = -1;
|
bClosestLevel = -1;
|
||||||
|
|
||||||
|
|
||||||
// NOTE: THIS FUNCTION ALLOWS RETURN OF UNCONSCIOUS AND UNREACHABLE OPPONENTS
|
// NOTE: THIS FUNCTION ALLOWS RETURN OF UNCONSCIOUS AND UNREACHABLE OPPONENTS
|
||||||
psLastLoc = &(gsLastKnownOppLoc[pSoldier->ubID][0]);
|
psLastLoc = &(gsLastKnownOppLoc[pSoldier->ubID][0]);
|
||||||
|
|
||||||
@@ -1394,33 +1405,33 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
|||||||
// look through this man's personal & public opplists for opponents known
|
// look through this man's personal & public opplists for opponents known
|
||||||
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
||||||
{
|
{
|
||||||
pOpp = MercSlots[ uiLoop ];
|
pOpponent = MercSlots[ uiLoop ];
|
||||||
|
|
||||||
// if this merc is inactive, at base, on assignment, or dead
|
// if this merc is inactive, at base, on assignment, or dead
|
||||||
if (!pOpp)
|
if (!pOpponent)
|
||||||
{
|
{
|
||||||
continue; // next merc
|
continue; // next merc
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this merc is neutral/on same side, he's not an opponent
|
// if this merc is neutral/on same side, he's not an opponent
|
||||||
if ( CONSIDERED_NEUTRAL( pSoldier, pOpp ) || (pSoldier->bSide == pOpp->bSide))
|
if ( CONSIDERED_NEUTRAL( pSoldier, pOpponent ) || (pSoldier->bSide == pOpponent->bSide))
|
||||||
{
|
{
|
||||||
continue; // next merc
|
continue; // next merc
|
||||||
}
|
}
|
||||||
|
|
||||||
// silversurfer: ignore empty vehicles
|
// silversurfer: ignore empty vehicles
|
||||||
if ( pOpp->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle( pOpp->bVehicleID ) == 0 )
|
if ( pOpponent->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle( pOpponent->bVehicleID ) == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Special stuff for Carmen the bounty hunter
|
// Special stuff for Carmen the bounty hunter
|
||||||
if (pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpp->ubProfile != SLAY)
|
if (pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpponent->ubProfile != SLAY)
|
||||||
{
|
{
|
||||||
continue; // next opponent
|
continue; // next opponent
|
||||||
}
|
}
|
||||||
|
|
||||||
pbPersOL = pSoldier->aiData.bOppList + pOpp->ubID;
|
pbPersOL = pSoldier->aiData.bOppList + pOpponent->ubID;
|
||||||
pbPublOL = gbPublicOpplist[pSoldier->bTeam] + pOpp->ubID;
|
pbPublOL = gbPublicOpplist[pSoldier->bTeam] + pOpponent->ubID;
|
||||||
psLastLoc = gsLastKnownOppLoc[pSoldier->ubID] + pOpp->ubID;
|
psLastLoc = gsLastKnownOppLoc[pSoldier->ubID] + pOpponent->ubID;
|
||||||
|
|
||||||
// if this opponent is unknown personally and publicly
|
// if this opponent is unknown personally and publicly
|
||||||
if ((*pbPersOL == NOT_HEARD_OR_SEEN) && (*pbPublOL == NOT_HEARD_OR_SEEN))
|
if ((*pbPersOL == NOT_HEARD_OR_SEEN) && (*pbPublOL == NOT_HEARD_OR_SEEN))
|
||||||
@@ -1433,14 +1444,14 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
|||||||
(*pbPersOL == *pbPublOL))
|
(*pbPersOL == *pbPublOL))
|
||||||
{
|
{
|
||||||
// using personal knowledge, obtain opponent's "best guess" gridno
|
// using personal knowledge, obtain opponent's "best guess" gridno
|
||||||
sGridNo = gsLastKnownOppLoc[pSoldier->ubID][pOpp->ubID];
|
sGridNo = gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID];
|
||||||
bLevel = gbLastKnownOppLevel[pSoldier->ubID][pOpp->ubID];
|
bLevel = gbLastKnownOppLevel[pSoldier->ubID][pOpponent->ubID];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// using public knowledge, obtain opponent's "best guess" gridno
|
// using public knowledge, obtain opponent's "best guess" gridno
|
||||||
sGridNo = gsPublicLastKnownOppLoc[pSoldier->bTeam][pOpp->ubID];
|
sGridNo = gsPublicLastKnownOppLoc[pSoldier->bTeam][pOpponent->ubID];
|
||||||
bLevel = gbPublicLastKnownOppLevel[pSoldier->bTeam][pOpp->ubID];
|
bLevel = gbPublicLastKnownOppLevel[pSoldier->bTeam][pOpponent->ubID];
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are standing at that gridno(!, obviously our info is old...)
|
// if we are standing at that gridno(!, obviously our info is old...)
|
||||||
@@ -1461,11 +1472,14 @@ INT32 ClosestKnownOpponent(SOLDIERTYPE *pSoldier, INT32 * psGridNo, INT8 * pbLev
|
|||||||
//sRange = PythSpacesAway( pSoldier->sGridNo, sGridNo);
|
//sRange = PythSpacesAway( pSoldier->sGridNo, sGridNo);
|
||||||
iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo );
|
iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo );
|
||||||
|
|
||||||
if (iRange < iClosestRange)
|
if (sClosestOpponent == NOWHERE ||
|
||||||
|
iRange < iClosestRange ||
|
||||||
|
pClosestOpponent && !pClosestOpponent->IsZombie() && pClosestOpponent->stats.bLife < OKLIFE && pOpponent->stats.bLife >= OKLIFE)
|
||||||
{
|
{
|
||||||
iClosestRange = iRange;
|
iClosestRange = iRange;
|
||||||
sClosestOpponent = sGridNo;
|
sClosestOpponent = sGridNo;
|
||||||
bClosestLevel = bLevel;
|
bClosestLevel = bLevel;
|
||||||
|
pClosestOpponent = pOpponent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4347,6 +4361,12 @@ UINT8 RedSmokeDanger(INT32 sGridNo, INT8 bLevel)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deep water should be safe
|
||||||
|
if (DeepWater(sGridNo, bLevel))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// no danger when in dense terrain
|
// no danger when in dense terrain
|
||||||
if (bLevel == 0 && TerrainDensity(sGridNo, bLevel, 2, FALSE) >= 20)
|
if (bLevel == 0 && TerrainDensity(sGridNo, bLevel, 2, FALSE) >= 20)
|
||||||
{
|
{
|
||||||
@@ -4702,7 +4722,7 @@ BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight)
|
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo)
|
||||||
{
|
{
|
||||||
if (!pSoldier)
|
if (!pSoldier)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4710,24 +4730,32 @@ UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater,
|
|||||||
if (TileIsOutOfBounds(sGridNo))
|
if (TileIsOutOfBounds(sGridNo))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
BOOLEAN fCautious = FALSE;
|
BOOLEAN fAlerted = FALSE;
|
||||||
BOOLEAN fGreen = FALSE;
|
BOOLEAN fGreen = FALSE;
|
||||||
|
BOOLEAN fProfile = FALSE;
|
||||||
|
BOOLEAN fNeutral = FALSE;
|
||||||
UINT8 ubLevel = 0;
|
UINT8 ubLevel = 0;
|
||||||
|
|
||||||
if ((pSoldier->aiData.bAlertStatus >= STATUS_RED || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE))
|
|
||||||
fCautious = TRUE;
|
|
||||||
|
|
||||||
if (pSoldier->aiData.bAlertStatus < STATUS_YELLOW)
|
if (pSoldier->aiData.bAlertStatus < STATUS_YELLOW)
|
||||||
fGreen = TRUE;
|
fGreen = TRUE;
|
||||||
|
|
||||||
if (!gGameExternalOptions.fAITacticalRetreat && NorthSpot(sGridNo, pSoldier->pathing.bLevel) ||
|
if (pSoldier->ubProfile != NO_PROFILE)
|
||||||
pSoldier->ubProfile == NO_PROFILE && fGreen && CheckDoorNearGridno(sGridNo))
|
fProfile = TRUE;
|
||||||
|
|
||||||
|
if (pSoldier->aiData.bNeutral)
|
||||||
|
fNeutral = TRUE;
|
||||||
|
|
||||||
|
if ((pSoldier->aiData.bAlertStatus >= STATUS_RED || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE))
|
||||||
|
fAlerted = TRUE;
|
||||||
|
|
||||||
|
if (!fProfile && !fNeutral && !gGameExternalOptions.fAITacticalRetreat && NorthSpot(sGridNo, pSoldier->pathing.bLevel) ||
|
||||||
|
!fProfile && fGreen && CheckDoorNearGridno(sGridNo))
|
||||||
ubLevel = 1;
|
ubLevel = 1;
|
||||||
|
|
||||||
if (fCautious && (fCheckLight && InLightAtNight(sGridNo, pSoldier->pathing.bLevel) || FindNearbyExplosiveStructure(sGridNo, pSoldier->pathing.bLevel)))
|
if (fAlerted && !fNeutral && (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) || FindNearbyExplosiveStructure(sGridNo, pSoldier->pathing.bLevel)))
|
||||||
ubLevel = 2;
|
ubLevel = 2;
|
||||||
|
|
||||||
if (fCheckWater && DeepWater(sGridNo, pSoldier->pathing.bLevel) ||
|
if (DeepWater(sGridNo, pSoldier->pathing.bLevel) ||
|
||||||
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
|
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
|
||||||
ubLevel = 3;
|
ubLevel = 3;
|
||||||
|
|
||||||
@@ -4738,7 +4766,7 @@ UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater,
|
|||||||
return ubLevel;
|
return ubLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight)
|
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo)
|
||||||
{
|
{
|
||||||
if (!pSoldier)
|
if (!pSoldier)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -4747,9 +4775,9 @@ BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheck
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// find current danger level
|
// find current danger level
|
||||||
UINT8 ubLevel = SpotDangerLevel(pSoldier, pSoldier->sGridNo, fCheckWater, fCheckLight);
|
UINT8 ubLevel = SpotDangerLevel(pSoldier, pSoldier->sGridNo);
|
||||||
// find danger level at target spot
|
// find danger level at target spot
|
||||||
UINT8 ubTargetLevel = SpotDangerLevel(pSoldier, sGridNo, fCheckWater, fCheckLight);
|
UINT8 ubTargetLevel = SpotDangerLevel(pSoldier, sGridNo);
|
||||||
|
|
||||||
// avoid moving into dangerous spot
|
// avoid moving into dangerous spot
|
||||||
if (ubTargetLevel > 0 && ubTargetLevel >= ubLevel)
|
if (ubTargetLevel > 0 && ubTargetLevel >= ubLevel)
|
||||||
@@ -4757,3 +4785,19 @@ BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheck
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN AllowDeepWaterFlanking(SOLDIERTYPE *pSoldier)
|
||||||
|
{
|
||||||
|
if (SoldierAI(pSoldier) &&
|
||||||
|
pSoldier->bTeam == ENEMY_TEAM &&
|
||||||
|
pSoldier->aiData.bOrders == SEEKENEMY &&
|
||||||
|
(pSoldier->aiData.bAttitude == CUNNINGSOLO || gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT(pSoldier, ATHLETICS_NT)) &&
|
||||||
|
pSoldier->aiData.bAlertStatus >= STATUS_RED &&
|
||||||
|
!pSoldier->aiData.bUnderFire &&
|
||||||
|
!GuySawEnemy(pSoldier))
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|||||||
+36
-4
@@ -655,6 +655,12 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
|
|||||||
iAttackValue /= 4;
|
iAttackValue /= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sevenfm: dying, cowering or unconscious soldiers have very low priority
|
||||||
|
if( pOpponent->stats.bLife < OKLIFE || pOpponent->bCollapsed || pOpponent->bBreathCollapsed )
|
||||||
|
{
|
||||||
|
iAttackValue /= 4;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUGATTACKS
|
#ifdef DEBUGATTACKS
|
||||||
DebugAI( String( "CalcBestShot: best AttackValue vs %d = %d\n",uiLoop,iAttackValue ) );
|
DebugAI( String( "CalcBestShot: best AttackValue vs %d = %d\n",uiLoop,iAttackValue ) );
|
||||||
#endif
|
#endif
|
||||||
@@ -670,14 +676,32 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns
|
|||||||
iPercentBetter = ((ubChanceToReallyHit * 100) / pBestShot->ubChanceToReallyHit) - 100;
|
iPercentBetter = ((ubChanceToReallyHit * 100) / pBestShot->ubChanceToReallyHit) - 100;
|
||||||
|
|
||||||
//dnl ch62 180813 ignore firing into breathless targets if there are targets in better condition
|
//dnl ch62 180813 ignore firing into breathless targets if there are targets in better condition
|
||||||
if((Menptr[pBestShot->ubOpponent].bCollapsed || Menptr[pBestShot->ubOpponent].bBreathCollapsed) && Menptr[pBestShot->ubOpponent].bBreath < OKBREATH && Menptr[pBestShot->ubOpponent].bBreath < pOpponent->bBreath)
|
// sevenfm: check that best opponent exists
|
||||||
|
if (pBestShot->ubOpponent != NOBODY &&
|
||||||
|
(Menptr[pBestShot->ubOpponent].bCollapsed || Menptr[pBestShot->ubOpponent].bBreathCollapsed) &&
|
||||||
|
Menptr[pBestShot->ubOpponent].bBreath < OKBREATH
|
||||||
|
&& Menptr[pBestShot->ubOpponent].bBreath < pOpponent->bBreath)
|
||||||
|
{
|
||||||
iPercentBetter = PERCENT_TO_IGNORE_THREAT;
|
iPercentBetter = PERCENT_TO_IGNORE_THREAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sevenfm: if best opponent is dying and new opponent is ok, use new opponent
|
||||||
|
if (pBestShot->ubOpponent != NOBODY &&
|
||||||
|
Menptr[pBestShot->ubOpponent].stats.bLife < OKLIFE &&
|
||||||
|
pOpponent->stats.bLife >= OKLIFE)
|
||||||
|
{
|
||||||
|
iPercentBetter = PERCENT_TO_IGNORE_THREAT;
|
||||||
|
}
|
||||||
|
|
||||||
// if this chance to really hit is more than 50% worse, and the other
|
// if this chance to really hit is more than 50% worse, and the other
|
||||||
// guy is conscious at all
|
// guy is conscious at all
|
||||||
if ((iPercentBetter < -PERCENT_TO_IGNORE_THREAT) && (Menptr[pBestShot->ubOpponent].stats.bLife >= OKLIFE))
|
if (iPercentBetter < -PERCENT_TO_IGNORE_THREAT &&
|
||||||
|
pBestShot->ubOpponent != NOBODY &&
|
||||||
|
Menptr[pBestShot->ubOpponent].stats.bLife >= OKLIFE)
|
||||||
|
{
|
||||||
// then stick with the older guy as the better target
|
// then stick with the older guy as the better target
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if this chance to really hit between 50% worse to 50% better
|
// if this chance to really hit between 50% worse to 50% better
|
||||||
if (iPercentBetter < PERCENT_TO_IGNORE_THREAT)
|
if (iPercentBetter < PERCENT_TO_IGNORE_THREAT)
|
||||||
@@ -1805,17 +1829,23 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt
|
|||||||
|
|
||||||
// if this chance to really hit is more than 50% worse, and the other
|
// if this chance to really hit is more than 50% worse, and the other
|
||||||
// guy is conscious at all
|
// guy is conscious at all
|
||||||
if ((iPercentBetter < -PERCENT_TO_IGNORE_THREAT) && (Menptr[pBestStab->ubOpponent].stats.bLife >= OKLIFE))
|
if (iPercentBetter < -PERCENT_TO_IGNORE_THREAT &&
|
||||||
|
pBestStab->ubOpponent != NOBODY &&
|
||||||
|
Menptr[pBestStab->ubOpponent].stats.bLife >= OKLIFE)
|
||||||
|
{
|
||||||
// then stick with the older guy as the better target
|
// then stick with the older guy as the better target
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if this chance to really hit between 50% worse to 50% better
|
// if this chance to really hit between 50% worse to 50% better
|
||||||
if (iPercentBetter < PERCENT_TO_IGNORE_THREAT)
|
if (iPercentBetter < PERCENT_TO_IGNORE_THREAT)
|
||||||
{
|
{
|
||||||
// then the one with the higher ATTACK VALUE is the better target
|
// then the one with the higher ATTACK VALUE is the better target
|
||||||
if (iAttackValue < pBestStab->iAttackValue)
|
if (iAttackValue < pBestStab->iAttackValue)
|
||||||
|
{
|
||||||
// the previous guy is more important since he's more dangerous
|
// the previous guy is more important since he's more dangerous
|
||||||
continue; // next opponent
|
continue; // next opponent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2004,7 +2034,9 @@ UINT8 NumMercsCloseTo( INT32 sGridNo, UINT8 ubMaxDist )
|
|||||||
{
|
{
|
||||||
pSoldier = MercSlots[ uiLoop ];
|
pSoldier = MercSlots[ uiLoop ];
|
||||||
|
|
||||||
if ( pSoldier && pSoldier->bTeam == gbPlayerNum && pSoldier->stats.bLife >= OKLIFE )
|
// sevenfm: count all teams except creatures
|
||||||
|
if (pSoldier && pSoldier->bTeam != CREATURE_TEAM && pSoldier->stats.bLife >= OKLIFE)
|
||||||
|
//if ( pSoldier && pSoldier->bTeam == gbPlayerNum && pSoldier->stats.bLife >= OKLIFE )
|
||||||
{
|
{
|
||||||
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= ubMaxDist)
|
if (PythSpacesAway( sGridNo, pSoldier->sGridNo ) <= ubMaxDist)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -780,7 +780,7 @@ INT8 CreatureDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the location of the closest reachable opponent
|
// get the location of the closest reachable opponent
|
||||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier,ubUnconsciousOK, &fChangeLevel);
|
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fChangeLevel);
|
||||||
// if there is an opponent reachable
|
// if there is an opponent reachable
|
||||||
if (!TileIsOutOfBounds(sClosestDisturbance))
|
if (!TileIsOutOfBounds(sClosestDisturbance))
|
||||||
{
|
{
|
||||||
@@ -1160,7 +1160,7 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier )
|
|||||||
if (pSoldier->aiData.bAttitude != AGGRESSIVE)
|
if (pSoldier->aiData.bAttitude != AGGRESSIVE)
|
||||||
{
|
{
|
||||||
// get the location of the closest CONSCIOUS reachable opponent
|
// get the location of the closest CONSCIOUS reachable opponent
|
||||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier,FALSE,&fChangeLevel);
|
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fChangeLevel);
|
||||||
|
|
||||||
// if we found one
|
// if we found one
|
||||||
if (!TileIsOutOfBounds(sClosestDisturbance))
|
if (!TileIsOutOfBounds(sClosestDisturbance))
|
||||||
|
|||||||
+66
-47
@@ -60,13 +60,13 @@ UINT32 guiRedSeekCounter = 0, guiRedHelpCounter = 0; guiRedHideCounter = 0;
|
|||||||
|
|
||||||
INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier);
|
INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier);
|
||||||
INT8 ZombieDecideActionYellow(SOLDIERTYPE *pSoldier);
|
INT8 ZombieDecideActionYellow(SOLDIERTYPE *pSoldier);
|
||||||
INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK);
|
INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier);
|
||||||
INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier);
|
INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
INT8 ArmedVehicleDecideActionGreen( SOLDIERTYPE *pSoldier );
|
INT8 ArmedVehicleDecideActionGreen(SOLDIERTYPE *pSoldier);
|
||||||
INT8 ArmedVehicleDecideActionYellow( SOLDIERTYPE *pSoldier );
|
INT8 ArmedVehicleDecideActionYellow(SOLDIERTYPE *pSoldier);
|
||||||
INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK );
|
INT8 ArmedVehicleDecideActionRed(SOLDIERTYPE *pSoldier);
|
||||||
INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier );
|
INT8 ArmedVehicleDecideActionBlack(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
void DoneScheduleAction( SOLDIERTYPE * pSoldier )
|
void DoneScheduleAction( SOLDIERTYPE * pSoldier )
|
||||||
{
|
{
|
||||||
@@ -690,7 +690,7 @@ INT8 DecideActionNamedNPC( SOLDIERTYPE * pSoldier )
|
|||||||
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||||
{
|
{
|
||||||
DOUBLE iChance, iSneaky = 10;
|
DOUBLE iChance, iSneaky = 10;
|
||||||
INT8 bInWater,bInGas;
|
INT8 bInWater, bInDeepWater, bInGas;
|
||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
STR16 tempstr;
|
STR16 tempstr;
|
||||||
#endif
|
#endif
|
||||||
@@ -796,7 +796,8 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInWater = Water(pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
||||||
|
bInDeepWater = DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
||||||
|
|
||||||
// check if standing in tear gas without a gas mask on, or in smoke
|
// check if standing in tear gas without a gas mask on, or in smoke
|
||||||
bInGas = InGasOrSmoke( pSoldier, pSoldier->sGridNo );
|
bInGas = InGasOrSmoke( pSoldier, pSoldier->sGridNo );
|
||||||
@@ -882,7 +883,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
|||||||
// if not in the way, do nothing most of the time
|
// if not in the way, do nothing most of the time
|
||||||
// unless in water (could've started there), then we better swim to shore!
|
// unless in water (could've started there), then we better swim to shore!
|
||||||
|
|
||||||
if (!(bInWater) && PreRandom( 5 ) )
|
if (!(bInDeepWater) && PreRandom( 5 ) )
|
||||||
{
|
{
|
||||||
// don't do nuttin!
|
// don't do nuttin!
|
||||||
return( AI_ACTION_NONE );
|
return( AI_ACTION_NONE );
|
||||||
@@ -1084,7 +1085,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
|||||||
|
|
||||||
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: get out of water and gas"));
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: get out of water and gas"));
|
||||||
|
|
||||||
if (bInWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
if (bInDeepWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||||
{
|
{
|
||||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||||
|
|
||||||
@@ -2439,7 +2440,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||||
{
|
{
|
||||||
INT8 bActionReturned;
|
INT8 bActionReturned;
|
||||||
INT32 iDummy;
|
INT32 iDummy;
|
||||||
@@ -2468,7 +2469,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
|
|
||||||
// Flugente: to prevent an accidental call
|
// Flugente: to prevent an accidental call
|
||||||
if ( pSoldier->IsZombie() )
|
if ( pSoldier->IsZombie() )
|
||||||
return( ZombieDecideActionRed(pSoldier, ubUnconsciousOK) );
|
return ZombieDecideActionRed(pSoldier);
|
||||||
|
|
||||||
// WANNE: Headrock informed me that I should remove that because it needs a lot of CPU!
|
// WANNE: Headrock informed me that I should remove that because it needs a lot of CPU!
|
||||||
// HEADROCK HAM B2.7: Calculate the overall tactical situation
|
// HEADROCK HAM B2.7: Calculate the overall tactical situation
|
||||||
@@ -2549,7 +2550,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
|
|
||||||
// determine if we happen to be in water (in which case we're in BIG trouble!)
|
// determine if we happen to be in water (in which case we're in BIG trouble!)
|
||||||
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||||
bInDeepWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInDeepWater = DeepWater( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||||
|
|
||||||
// check if standing in tear gas without a gas mask on
|
// check if standing in tear gas without a gas mask on
|
||||||
bInGas = InGasOrSmoke( pSoldier, pSoldier->sGridNo );
|
bInGas = InGasOrSmoke( pSoldier, pSoldier->sGridNo );
|
||||||
@@ -2582,6 +2583,18 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
// WHEN IN GAS, GO TO NEAREST REACHABLE SPOT OF UNGASSED LAND
|
// WHEN IN GAS, GO TO NEAREST REACHABLE SPOT OF UNGASSED LAND
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// when in deep water, move to closest opponent
|
||||||
|
if (ubCanMove && bInDeepWater && !pSoldier->aiData.bNeutral && pSoldier->aiData.bOrders == SEEKENEMY)
|
||||||
|
{
|
||||||
|
// find closest reachable opponent, excluding opponents in deep water
|
||||||
|
pSoldier->aiData.usActionData = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||||
|
|
||||||
|
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||||
|
{
|
||||||
|
return(AI_ACTION_LEAVE_WATER_GAS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ubCanMove && (bInGas || bInDeepWater || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)))
|
if (ubCanMove && (bInGas || bInDeepWater || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)))
|
||||||
{
|
{
|
||||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||||
@@ -3361,7 +3374,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// get the location of the closest reachable opponent
|
// get the location of the closest reachable opponent
|
||||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier,ubUnconsciousOK, &fClimb);
|
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||||
|
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: check to continue flanking");
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: check to continue flanking");
|
||||||
// continue flanking
|
// continue flanking
|
||||||
@@ -4013,7 +4026,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
// let's be a bit cautious about going right up to a location without enough APs to shoot
|
// let's be a bit cautious about going right up to a location without enough APs to shoot
|
||||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||||
{
|
{
|
||||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, ubUnconsciousOK, &fClimb);
|
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||||
if (!TileIsOutOfBounds(sClosestDisturbance) && ( SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) + 5 < SpacesAway( pSoldier->sGridNo, sClosestDisturbance ) ) )
|
if (!TileIsOutOfBounds(sClosestDisturbance) && ( SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) + 5 < SpacesAway( pSoldier->sGridNo, sClosestDisturbance ) ) )
|
||||||
{
|
{
|
||||||
// either moving significantly closer or into very close range
|
// either moving significantly closer or into very close range
|
||||||
@@ -4338,7 +4351,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// if not in combat or under fire, and we COULD have moved, just chose not to
|
// if not in combat or under fire, and we COULD have moved, just chose not to
|
||||||
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && ( TileIsOutOfBounds(ClosestReachableDisturbance(pSoldier, TRUE, &fClimb))) )
|
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && ( TileIsOutOfBounds(ClosestReachableDisturbance(pSoldier, &fClimb))) )
|
||||||
{
|
{
|
||||||
// addition: if soldier is bleeding then reduce bleeding and do nothing
|
// addition: if soldier is bleeding then reduce bleeding and do nothing
|
||||||
if ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD )
|
if ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD )
|
||||||
@@ -4718,6 +4731,18 @@ INT16 ubMinAPCost;
|
|||||||
// STUCK IN WATER OR GAS, NO COVER, GO TO NEAREST SPOT OF UNGASSED LAND
|
// STUCK IN WATER OR GAS, NO COVER, GO TO NEAREST SPOT OF UNGASSED LAND
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// when in deep water, move to closest opponent
|
||||||
|
if (ubCanMove && bInDeepWater && !pSoldier->aiData.bNeutral && pSoldier->aiData.bOrders == SEEKENEMY)
|
||||||
|
{
|
||||||
|
// find closest reachable opponent, excluding opponents in deep water
|
||||||
|
pSoldier->aiData.usActionData = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||||
|
|
||||||
|
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||||
|
{
|
||||||
|
return(AI_ACTION_LEAVE_WATER_GAS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if soldier in water/gas has enough APs left to move at least 1 square
|
// if soldier in water/gas has enough APs left to move at least 1 square
|
||||||
if (ubCanMove && (bInGas || bInDeepWater || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)))
|
if (ubCanMove && (bInGas || bInDeepWater || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)))
|
||||||
{
|
{
|
||||||
@@ -5073,28 +5098,23 @@ INT16 ubMinAPCost;
|
|||||||
// (usually, this means all the guys we see are unconscious, but, on
|
// (usually, this means all the guys we see are unconscious, but, on
|
||||||
// rare occasions, we may not be able to shoot a healthy guy, too)
|
// rare occasions, we may not be able to shoot a healthy guy, too)
|
||||||
if ((Menptr[BestShot.ubOpponent].stats.bLife < OKLIFE) &&
|
if ((Menptr[BestShot.ubOpponent].stats.bLife < OKLIFE) &&
|
||||||
!Menptr[BestShot.ubOpponent].bService)
|
!Menptr[BestShot.ubOpponent].bService &&
|
||||||
|
(pSoldier->aiData.bAttitude != AGGRESSIVE || Chance((100 - BestShot.ubChanceToReallyHit) / 2)))
|
||||||
{
|
{
|
||||||
// if our attitude is NOT aggressive
|
// get the location of the closest CONSCIOUS reachable opponent
|
||||||
if ( pSoldier->aiData.bAttitude != AGGRESSIVE || BestShot.ubChanceToReallyHit < 60 )
|
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||||
{
|
|
||||||
// get the location of the closest CONSCIOUS reachable opponent
|
|
||||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier,FALSE, &fClimb);
|
|
||||||
|
|
||||||
// if we found one
|
// if we found one
|
||||||
if (!TileIsOutOfBounds(sClosestDisturbance))
|
if (!TileIsOutOfBounds(sClosestDisturbance))
|
||||||
{
|
{
|
||||||
// don't bother checking GRENADES/KNIVES, he can't have conscious targets
|
// don't bother checking GRENADES/KNIVES, he can't have conscious targets
|
||||||
#ifdef RECORDNET
|
#ifdef RECORDNET
|
||||||
fprintf(NetDebugFile,"\tDecideActionBlack: all visible opponents unconscious, switching to RED AI...\n");
|
fprintf(NetDebugFile,"\tDecideActionBlack: all visible opponents unconscious, switching to RED AI...\n");
|
||||||
#endif
|
#endif
|
||||||
// then make decision as if at alert status RED, but make sure
|
// then make decision as if at alert status RED
|
||||||
// we don't try to SEEK OPPONENT the unconscious guy!
|
return DecideActionRed(pSoldier);
|
||||||
return(DecideActionRed(pSoldier,FALSE));
|
|
||||||
}
|
|
||||||
// else kill the guy, he could be the last opponent alive in this sector
|
|
||||||
}
|
}
|
||||||
// else aggressive guys will ALWAYS finish off unconscious opponents
|
// else kill the guy, he could be the last opponent alive in this sector
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we KNOW FOR SURE that we will do something (shoot, at least)
|
// now we KNOW FOR SURE that we will do something (shoot, at least)
|
||||||
@@ -7423,7 +7443,7 @@ INT8 ZombieDecideActionYellow(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier)
|
||||||
{
|
{
|
||||||
INT32 iDummy;
|
INT32 iDummy;
|
||||||
INT32 iChance,sClosestOpponent,sClosestFriend;
|
INT32 iChance,sClosestOpponent,sClosestFriend;
|
||||||
@@ -7457,7 +7477,7 @@ INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
|
|
||||||
// determine if we happen to be in water (in which case we're in BIG trouble!)
|
// determine if we happen to be in water (in which case we're in BIG trouble!)
|
||||||
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||||
bInDeepWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInDeepWater = DeepWater( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||||
|
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: crouch and rest if running out of breath");
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: crouch and rest if running out of breath");
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@@ -7485,7 +7505,7 @@ INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// get the location of the closest reachable opponent
|
// get the location of the closest reachable opponent
|
||||||
sClosestDisturbance = ClosestReachableDisturbance(pSoldier,ubUnconsciousOK, &fClimb);
|
sClosestDisturbance = ClosestReachableDisturbance(pSoldier, &fClimb);
|
||||||
|
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: check to continue flanking");
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: check to continue flanking");
|
||||||
// continue flanking
|
// continue flanking
|
||||||
@@ -7583,7 +7603,6 @@ INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
// zombies don't hide, they seek prey...
|
// zombies don't hide, they seek prey...
|
||||||
bSeekPts = 99;
|
bSeekPts = 99;
|
||||||
bHelpPts = 40;
|
bHelpPts = 40;
|
||||||
bWatchPts -= 10;
|
|
||||||
|
|
||||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("decideactionred: checking seek/help/watch points... orders = %d, attitude = %d",pSoldier->aiData.bOrders,pSoldier->aiData.bAttitude));
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("decideactionred: checking seek/help/watch points... orders = %d, attitude = %d",pSoldier->aiData.bOrders,pSoldier->aiData.bAttitude));
|
||||||
// calculate initial points for watch based on highest watch loc
|
// calculate initial points for watch based on highest watch loc
|
||||||
@@ -8051,7 +8070,7 @@ INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// if not in combat or under fire, and we COULD have moved, just chose not to
|
// if not in combat or under fire, and we COULD have moved, just chose not to
|
||||||
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && ( TileIsOutOfBounds(ClosestReachableDisturbance(pSoldier, TRUE, &fClimb))) )
|
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && ( TileIsOutOfBounds(ClosestReachableDisturbance(pSoldier, &fClimb))) )
|
||||||
{
|
{
|
||||||
// addition: if soldier is bleeding then reduce bleeding and do nothing
|
// addition: if soldier is bleeding then reduce bleeding and do nothing
|
||||||
/*if ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD )
|
/*if ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD )
|
||||||
@@ -8845,7 +8864,7 @@ INT8 ZombieDecideAction( SOLDIERTYPE *pSoldier )
|
|||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
AIPopMessage("AlertStatus = RED");
|
AIPopMessage("AlertStatus = RED");
|
||||||
#endif
|
#endif
|
||||||
bAction = ZombieDecideActionRed(pSoldier, TRUE);
|
bAction = ZombieDecideActionRed(pSoldier);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATUS_BLACK:
|
case STATUS_BLACK:
|
||||||
@@ -8890,7 +8909,7 @@ INT8 ArmedVehicleDecideAction( SOLDIERTYPE *pSoldier )
|
|||||||
#ifdef DEBUGDECISIONS
|
#ifdef DEBUGDECISIONS
|
||||||
AIPopMessage( "AlertStatus = RED" );
|
AIPopMessage( "AlertStatus = RED" );
|
||||||
#endif
|
#endif
|
||||||
bAction = ArmedVehicleDecideActionRed( pSoldier, TRUE );
|
bAction = ArmedVehicleDecideActionRed(pSoldier);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATUS_BLACK:
|
case STATUS_BLACK:
|
||||||
@@ -9790,7 +9809,7 @@ INT8 ArmedVehicleDecideActionYellow( SOLDIERTYPE *pSoldier )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK )
|
INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier)
|
||||||
{
|
{
|
||||||
INT32 iDummy;
|
INT32 iDummy;
|
||||||
INT32 iChance, sClosestOpponent, sClosestFriend;
|
INT32 iChance, sClosestOpponent, sClosestFriend;
|
||||||
@@ -9815,7 +9834,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK )
|
|||||||
|
|
||||||
// Flugente: to prevent an accidental call
|
// Flugente: to prevent an accidental call
|
||||||
if ( !ARMED_VEHICLE(pSoldier) )
|
if ( !ARMED_VEHICLE(pSoldier) )
|
||||||
return DecideActionRed( pSoldier, ubUnconsciousOK );
|
return DecideActionRed( pSoldier);
|
||||||
|
|
||||||
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "ArmedVehicleDecideActionRed: soldier orders = %d", pSoldier->aiData.bOrders ) );
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String( "ArmedVehicleDecideActionRed: soldier orders = %d", pSoldier->aiData.bOrders ) );
|
||||||
|
|
||||||
@@ -9837,7 +9856,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK )
|
|||||||
|
|
||||||
// determine if we happen to be in water (in which case we're in BIG trouble!)
|
// determine if we happen to be in water (in which case we're in BIG trouble!)
|
||||||
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||||
bInDeepWater = Water( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
bInDeepWater = DeepWater( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// IF POSSIBLE, FIRE LONG RANGE WEAPONS AT TARGETS REPORTED BY RADIO
|
// IF POSSIBLE, FIRE LONG RANGE WEAPONS AT TARGETS REPORTED BY RADIO
|
||||||
@@ -10200,7 +10219,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK )
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// get the location of the closest reachable opponent
|
// get the location of the closest reachable opponent
|
||||||
sClosestDisturbance = ClosestReachableDisturbance( pSoldier, ubUnconsciousOK, &fClimb );
|
sClosestDisturbance = ClosestReachableDisturbance( pSoldier, &fClimb );
|
||||||
|
|
||||||
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "ArmedVehicleDecideActionRed: check to continue flanking" );
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "ArmedVehicleDecideActionRed: check to continue flanking" );
|
||||||
// continue flanking
|
// continue flanking
|
||||||
@@ -10693,7 +10712,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK )
|
|||||||
// let's be a bit cautious about going right up to a location without enough APs to shoot
|
// let's be a bit cautious about going right up to a location without enough APs to shoot
|
||||||
if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) )
|
if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) )
|
||||||
{
|
{
|
||||||
sClosestDisturbance = ClosestReachableDisturbance( pSoldier, ubUnconsciousOK, &fClimb );
|
sClosestDisturbance = ClosestReachableDisturbance( pSoldier, &fClimb );
|
||||||
if ( !TileIsOutOfBounds( sClosestDisturbance ) && (SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) + 5 < SpacesAway( pSoldier->sGridNo, sClosestDisturbance )) )
|
if ( !TileIsOutOfBounds( sClosestDisturbance ) && (SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || SpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) + 5 < SpacesAway( pSoldier->sGridNo, sClosestDisturbance )) )
|
||||||
{
|
{
|
||||||
// either moving significantly closer or into very close range
|
// either moving significantly closer or into very close range
|
||||||
@@ -10912,7 +10931,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK )
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// if not in combat or under fire, and we COULD have moved, just chose not to
|
// if not in combat or under fire, and we COULD have moved, just chose not to
|
||||||
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && (TileIsOutOfBounds( ClosestReachableDisturbance( pSoldier, TRUE, &fClimb ) )) )
|
if ( (pSoldier->aiData.bAlertStatus != STATUS_BLACK) && !pSoldier->aiData.bUnderFire && ubCanMove && (!gfTurnBasedAI || pSoldier->bActionPoints >= pSoldier->bInitialActionPoints) && (TileIsOutOfBounds( ClosestReachableDisturbance( pSoldier, &fClimb ) )) )
|
||||||
{
|
{
|
||||||
#ifdef RECORDNET
|
#ifdef RECORDNET
|
||||||
fprintf( NetDebugFile, "\tArmedVehicleDecideActionRed: guynum %d switching to GREEN AI...\n", pSoldier->ubID );
|
fprintf( NetDebugFile, "\tArmedVehicleDecideActionRed: guynum %d switching to GREEN AI...\n", pSoldier->ubID );
|
||||||
@@ -11219,7 +11238,7 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
|||||||
if ( pSoldier->aiData.bAttitude != AGGRESSIVE || BestShot.ubChanceToReallyHit < 60 )
|
if ( pSoldier->aiData.bAttitude != AGGRESSIVE || BestShot.ubChanceToReallyHit < 60 )
|
||||||
{
|
{
|
||||||
// get the location of the closest CONSCIOUS reachable opponent
|
// get the location of the closest CONSCIOUS reachable opponent
|
||||||
sClosestDisturbance = ClosestReachableDisturbance( pSoldier, FALSE, &fClimb );
|
sClosestDisturbance = ClosestReachableDisturbance( pSoldier, &fClimb );
|
||||||
|
|
||||||
// if we found one
|
// if we found one
|
||||||
if ( !TileIsOutOfBounds( sClosestDisturbance ) )
|
if ( !TileIsOutOfBounds( sClosestDisturbance ) )
|
||||||
@@ -11230,7 +11249,7 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
|||||||
#endif
|
#endif
|
||||||
// then make decision as if at alert status RED, but make sure
|
// then make decision as if at alert status RED, but make sure
|
||||||
// we don't try to SEEK OPPONENT the unconscious guy!
|
// we don't try to SEEK OPPONENT the unconscious guy!
|
||||||
return(DecideActionRed( pSoldier, FALSE ));
|
return DecideActionRed(pSoldier);
|
||||||
}
|
}
|
||||||
// else kill the guy, he could be the last opponent alive in this sector
|
// else kill the guy, he could be the last opponent alive in this sector
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1499,7 +1499,7 @@ INT32 FindSpotMaxDistFromOpponents(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, TRUE))
|
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1578,14 +1578,12 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
|||||||
INT32 sGridNo, sClosestLand = NOWHERE, sPathCost, sShortestPath = 1000;
|
INT32 sGridNo, sClosestLand = NOWHERE, sPathCost, sShortestPath = 1000;
|
||||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||||
INT32 iSearchRange;
|
INT32 iSearchRange;
|
||||||
INT16 sDistance, sOriginalDistance;
|
|
||||||
UINT16 usMovementMode = DetermineMovementMode(pSoldier, AI_ACTION_LEAVE_WATER_GAS);
|
UINT16 usMovementMode = DetermineMovementMode(pSoldier, AI_ACTION_LEAVE_WATER_GAS);
|
||||||
|
BOOLEAN fFoundReachable = FALSE;
|
||||||
sOriginalDistance = DistanceToClosestActiveOpponent(pSoldier, pSoldier->sGridNo);
|
|
||||||
|
|
||||||
// start with a small search area, and expand it if we're unsuccessful
|
// start with a small search area, and expand it if we're unsuccessful
|
||||||
// this should almost never need to search farther than 5 or 10 squares...
|
// this should almost never need to search farther than 5 or 10 squares...
|
||||||
for (iSearchRange = 5; iSearchRange <= 25; iSearchRange += 10)
|
for (iSearchRange = 5; iSearchRange <= 35 && (fFoundReachable || iSearchRange <= 5); iSearchRange += 10)
|
||||||
{
|
{
|
||||||
//NumMessage("Trying iSearchRange = ", iSearchRange);
|
//NumMessage("Trying iSearchRange = ", iSearchRange);
|
||||||
|
|
||||||
@@ -1619,7 +1617,8 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gubNPCAPBudget = pSoldier->bActionPoints;
|
//gubNPCAPBudget = pSoldier->bActionPoints;
|
||||||
|
gubNPCAPBudget = 0;
|
||||||
gubNPCDistLimit = (UINT8)iSearchRange;
|
gubNPCDistLimit = (UINT8)iSearchRange;
|
||||||
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0); //dnl ch50 071009
|
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0); //dnl ch50 071009
|
||||||
gubNPCAPBudget = 0;
|
gubNPCAPBudget = 0;
|
||||||
@@ -1647,13 +1646,15 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fFoundReachable = TRUE;
|
||||||
|
|
||||||
// ignore blacklisted spot
|
// ignore blacklisted spot
|
||||||
if (sGridNo == pSoldier->pathing.sBlackList)
|
if (sGridNo == pSoldier->pathing.sBlackList)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, FALSE))
|
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1676,15 +1677,6 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sDistance = DistanceToClosestActiveOpponent(pSoldier, pSoldier->sGridNo);
|
|
||||||
|
|
||||||
// penalty if moving closer to enemy
|
|
||||||
if (sDistance >= 0 && sOriginalDistance >= 0 && sDistance < sOriginalDistance)
|
|
||||||
{
|
|
||||||
//sPathCost += APBPConstants[AP_MAXIMUM];
|
|
||||||
sPathCost += (sOriginalDistance - sDistance) * (APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_WALK]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this path is shorter than the one to the closest land found so far
|
// if this path is shorter than the one to the closest land found so far
|
||||||
if (sPathCost < sShortestPath)
|
if (sPathCost < sShortestPath)
|
||||||
{
|
{
|
||||||
@@ -1717,6 +1709,7 @@ INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
|
|||||||
INT32 iRoamRange;
|
INT32 iRoamRange;
|
||||||
INT32 sOrigin;
|
INT32 sOrigin;
|
||||||
UINT16 usMovementMode = DetermineMovementMode(pSoldier, AI_ACTION_LEAVE_WATER_GAS);
|
UINT16 usMovementMode = DetermineMovementMode(pSoldier, AI_ACTION_LEAVE_WATER_GAS);
|
||||||
|
BOOLEAN fFoundReachable = FALSE;
|
||||||
|
|
||||||
bCurrLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
bCurrLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
||||||
|
|
||||||
@@ -1724,7 +1717,7 @@ INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
|
|||||||
|
|
||||||
// start with a small search area, and expand it if we're unsuccessful
|
// start with a small search area, and expand it if we're unsuccessful
|
||||||
// this should almost never need to search farther than 5 or 10 squares...
|
// this should almost never need to search farther than 5 or 10 squares...
|
||||||
for (iSearchRange = 5; iSearchRange <= 15; iSearchRange += 5)
|
for (iSearchRange = 5; iSearchRange <= 25 && (fFoundReachable || iSearchRange <= 5); iSearchRange += 5)
|
||||||
{
|
{
|
||||||
// determine maximum horizontal limits
|
// determine maximum horizontal limits
|
||||||
sMaxLeft = min(iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
sMaxLeft = min(iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
||||||
@@ -1756,7 +1749,8 @@ INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gubNPCAPBudget = pSoldier->bActionPoints;
|
//gubNPCAPBudget = pSoldier->bActionPoints;
|
||||||
|
gubNPCAPBudget = 0;
|
||||||
gubNPCDistLimit = (UINT8)iSearchRange;
|
gubNPCDistLimit = (UINT8)iSearchRange;
|
||||||
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0); //dnl ch50 071009
|
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0); //dnl ch50 071009
|
||||||
gubNPCAPBudget = 0;
|
gubNPCAPBudget = 0;
|
||||||
@@ -1784,6 +1778,8 @@ INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fFoundReachable = TRUE;
|
||||||
|
|
||||||
// ignore blacklisted spot
|
// ignore blacklisted spot
|
||||||
if (sGridNo == pSoldier->pathing.sBlackList)
|
if (sGridNo == pSoldier->pathing.sBlackList)
|
||||||
{
|
{
|
||||||
@@ -1796,7 +1792,7 @@ INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, TRUE))
|
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1977,7 +1973,7 @@ INT8 SearchForItems( SOLDIERTYPE * pSoldier, INT8 bReason, UINT16 usItem )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, sGridNo, TRUE, FALSE))
|
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2716,7 +2712,8 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sevenfm: don't go into deep water for flanking
|
// sevenfm: don't go into deep water for flanking
|
||||||
if (DeepWater(sGridNo, pSoldier->pathing.bLevel) &&
|
if (!AllowDeepWaterFlanking(pSoldier) &&
|
||||||
|
DeepWater(sGridNo, pSoldier->pathing.bLevel) &&
|
||||||
!DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
!DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -2736,7 +2733,7 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckNPCDestination(pSoldier, sGridNo, FALSE, TRUE))
|
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -177,7 +177,7 @@ INT8 DecideAction(SOLDIERTYPE *pSoldier);
|
|||||||
INT8 DecideActionBlack(SOLDIERTYPE *pSoldier);
|
INT8 DecideActionBlack(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionEscort(SOLDIERTYPE *pSoldier);
|
INT8 DecideActionEscort(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier);
|
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK);
|
INT8 DecideActionRed(SOLDIERTYPE *pSoldier);
|
||||||
INT8 DecideActionYellow(SOLDIERTYPE *pSoldier);
|
INT8 DecideActionYellow(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
INT16 DistanceToClosestFriend( SOLDIERTYPE * pSoldier );
|
INT16 DistanceToClosestFriend( SOLDIERTYPE * pSoldier );
|
||||||
@@ -310,8 +310,9 @@ BOOLEAN ValidOpponent(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pOpponent);
|
|||||||
BOOLEAN AnyCoverFromSpot( INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThreatLevel );
|
BOOLEAN AnyCoverFromSpot( INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThreatLevel );
|
||||||
UINT8 CountSeenEnemiesLastTurn( SOLDIERTYPE *pSoldier );
|
UINT8 CountSeenEnemiesLastTurn( SOLDIERTYPE *pSoldier );
|
||||||
|
|
||||||
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight);
|
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
||||||
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckWater, BOOLEAN fCheckLight);
|
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
||||||
|
BOOLEAN AllowDeepWaterFlanking(SOLDIERTYPE *pSoldier);
|
||||||
|
|
||||||
BOOLEAN NorthSpot(INT32 sSpot, INT8 bLevel);
|
BOOLEAN NorthSpot(INT32 sSpot, INT8 bLevel);
|
||||||
BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier);
|
BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "random.h"
|
#include "random.h"
|
||||||
#include "render fun.h"
|
#include "render fun.h"
|
||||||
#include "GameSettings.h"
|
#include "GameSettings.h"
|
||||||
|
// sevenfm
|
||||||
|
#include "PATHAI.H"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern BOOLEAN gfBasement;
|
extern BOOLEAN gfBasement;
|
||||||
@@ -4176,3 +4178,48 @@ BOOLEAN IsLegionLevel( INT32 sGridNo )
|
|||||||
|
|
||||||
}
|
}
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
|
// sevenfm: check adjacent tiles
|
||||||
|
BOOLEAN FindNotDeepWaterNearby(INT32 sSpot, BOOLEAN bLevel)
|
||||||
|
{
|
||||||
|
UINT8 ubMovementCost;
|
||||||
|
INT32 sTempGridNo;
|
||||||
|
UINT8 ubDirection;
|
||||||
|
|
||||||
|
// check adjacent reachable tiles
|
||||||
|
for (ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ubDirection++)
|
||||||
|
{
|
||||||
|
sTempGridNo = NewGridNo(sSpot, DirectionInc(ubDirection));
|
||||||
|
ubMovementCost = gubWorldMovementCosts[sTempGridNo][ubDirection][bLevel];
|
||||||
|
|
||||||
|
if (ubMovementCost < TRAVELCOST_BLOCKED &&
|
||||||
|
!DeepWater(sTempGridNo, bLevel))
|
||||||
|
{
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN FindNotWaterNearby(INT32 sSpot, BOOLEAN bLevel)
|
||||||
|
{
|
||||||
|
UINT8 ubMovementCost;
|
||||||
|
INT32 sTempGridNo;
|
||||||
|
UINT8 ubDirection;
|
||||||
|
|
||||||
|
// check adjacent reachable tiles
|
||||||
|
for (ubDirection = 0; ubDirection < NUM_WORLD_DIRECTIONS; ubDirection++)
|
||||||
|
{
|
||||||
|
sTempGridNo = NewGridNo(sSpot, DirectionInc(ubDirection));
|
||||||
|
ubMovementCost = gubWorldMovementCosts[sTempGridNo][ubDirection][bLevel];
|
||||||
|
|
||||||
|
if (ubMovementCost < TRAVELCOST_BLOCKED &&
|
||||||
|
!Water(sTempGridNo, bLevel))
|
||||||
|
{
|
||||||
|
return(TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ UINT8 GetTerrainType( INT32 sGridNo );
|
|||||||
BOOLEAN Water( INT32 sGridNo, BOOLEAN bLevel );
|
BOOLEAN Water( INT32 sGridNo, BOOLEAN bLevel );
|
||||||
BOOLEAN DeepWater( INT32 sGridNo, BOOLEAN bLevel );
|
BOOLEAN DeepWater( INT32 sGridNo, BOOLEAN bLevel );
|
||||||
BOOLEAN WaterTooDeepForAttacks( INT32 sGridNo, BOOLEAN bLevel );
|
BOOLEAN WaterTooDeepForAttacks( INT32 sGridNo, BOOLEAN bLevel );
|
||||||
|
// sevenfm
|
||||||
|
BOOLEAN FindNotDeepWaterNearby(INT32 sSpot, BOOLEAN bLevel);
|
||||||
|
BOOLEAN FindNotWaterNearby(INT32 sSpot, BOOLEAN bLevel);
|
||||||
|
|
||||||
// Structure manipulation routines
|
// Structure manipulation routines
|
||||||
BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex );
|
BOOLEAN RemoveStruct( INT32 iMapIndex, UINT16 usIndex );
|
||||||
|
|||||||
Reference in New Issue
Block a user