mirror of
https://github.com/1dot13/source.git
synced 2026-07-29 13:52:17 +02:00
Enemy soldiers will try to avoid being hit by artillery strike.
FindBestNearbyCover: - penalty to locations in red smoke danger zone - avoid moving into red smoke danger zone if not in red smoke danger already FindNearestUngassedLand: - improved code - try not to move closer to known enemies. - calculate path with correct movement mode FindNearbyDarkerSpot: - improved code - calculate path with correct movement mode FindFlankingSpot: - avoid locations near bombs - avoid moving into red smoke danger zone git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8753 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -48,13 +48,6 @@ enum
|
||||
NUM_URGENCY_STATES
|
||||
};
|
||||
|
||||
#define NOWATER 0
|
||||
#define WATEROK 1
|
||||
|
||||
#define IGNORE_PATH 0
|
||||
#define ENSURE_PATH 1
|
||||
#define ENSURE_PATH_COST 2
|
||||
|
||||
#define DONTFORCE 0
|
||||
#define FORCE 1
|
||||
|
||||
@@ -95,7 +88,6 @@ enum
|
||||
#define MAX_THREAT_RANGE 400 // 30 tiles worth
|
||||
#define MIN_PERCENT_BETTER 5 // 5% improvement in cover is good
|
||||
|
||||
|
||||
#define TOSSES_PER_10TURNS 18 // max # of grenades tossable in 10 turns
|
||||
#define SHELLS_PER_10TURNS 13 // max # of shells firable in 10 turns
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "Game Clock.h" // sevenfm
|
||||
#include "Rotting Corpses.h" // sevenfm
|
||||
#include "wcheck.h" // sevenfm
|
||||
#include "SmokeEffects.h" // sevenfm
|
||||
#endif
|
||||
|
||||
#include "GameInitOptionsScreen.h"
|
||||
@@ -4255,6 +4256,266 @@ BOOLEAN FindBombNearby( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDistance )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// danger percent based on distance to closest smoke effect
|
||||
UINT8 RedSmokeDanger(INT32 sGridNo, INT8 bLevel)
|
||||
{
|
||||
UINT32 uiCnt;
|
||||
INT32 sDist;
|
||||
INT32 sClosestDist;
|
||||
INT32 sMaxDist = min(gSkillTraitValues.usVOMortarRadius, DAY_VISION_RANGE);
|
||||
INT32 sClosestSmoke = NOWHERE;
|
||||
UINT8 ubDangerPercent = 0;
|
||||
|
||||
if (TileIsOutOfBounds(sGridNo))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!gSkillTraitValues.fROAllowArtillery)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// no artillery strike danger underground
|
||||
if (gbWorldSectorZ > 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check if artillery strike was ordered by any team
|
||||
if (!CheckArtilleryStrike())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// no danger when in a building
|
||||
if (bLevel == 0 && CheckRoof(sGridNo))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// no danger when in dense terrain
|
||||
if (bLevel == 0 && TerrainDensity(sGridNo, bLevel, 2, FALSE) >= 20)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//loop through all red smoke effects and find closest
|
||||
for (uiCnt = 0; uiCnt < guiNumSmokeEffects; uiCnt++)
|
||||
{
|
||||
if (gSmokeEffectData[uiCnt].fAllocated &&
|
||||
gSmokeEffectData[uiCnt].bType == SIGNAL_SMOKE_EFFECT &&
|
||||
!TileIsOutOfBounds(gSmokeEffectData[uiCnt].sGridNo))
|
||||
{
|
||||
sDist = PythSpacesAway(gSmokeEffectData[uiCnt].sGridNo, sGridNo);
|
||||
|
||||
if (sClosestSmoke == NOWHERE || sDist < sClosestDist)
|
||||
{
|
||||
sClosestDist = sDist;
|
||||
sClosestSmoke = gSmokeEffectData[uiCnt].sGridNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we found red smoke, calculate danger percent based on distance
|
||||
// 0% at DAY_VISION_RANGE/2, 100% at zero range
|
||||
if (sClosestSmoke != NOWHERE)
|
||||
{
|
||||
ubDangerPercent = 100 * (sMaxDist - min(sMaxDist, sClosestDist)) / sMaxDist;
|
||||
}
|
||||
|
||||
return ubDangerPercent;
|
||||
}
|
||||
|
||||
// check if artillery strike was ordered by any team
|
||||
BOOLEAN CheckArtilleryStrike(void)
|
||||
{
|
||||
UINT32 uiBombIndex;
|
||||
OBJECTTYPE *pObj;
|
||||
|
||||
// search all bombs
|
||||
for (uiBombIndex = 0; uiBombIndex < guiNumWorldBombs; uiBombIndex++)
|
||||
{
|
||||
if (gWorldBombs[uiBombIndex].fExists &&
|
||||
gWorldItems[gWorldBombs[uiBombIndex].iItemIndex].usFlags & WORLD_ITEM_ARMED_BOMB)
|
||||
{
|
||||
pObj = &(gWorldItems[gWorldBombs[uiBombIndex].iItemIndex].object);
|
||||
|
||||
if (pObj && pObj->exists() && (*pObj)[0]->data.ubWireNetworkFlag & ANY_ARTILLERY_FLAG)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN CheckRoof(INT32 sGridNo)
|
||||
{
|
||||
if (FindStructure(sGridNo, STRUCTURE_ROOF) != NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT8 TerrainDensity(INT32 sSpot, INT8 bLevel, UINT8 ubDistance, BOOLEAN fGrass)
|
||||
{
|
||||
if (TileIsOutOfBounds(sSpot))
|
||||
return 0;
|
||||
|
||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||
INT32 sCheckSpot = NOWHERE;
|
||||
INT32 sCountSpots = 0;
|
||||
INT32 sCountObstacles = 0;
|
||||
UINT16 usRoom1, usRoom2;
|
||||
|
||||
STRUCTURE *pCurrent;
|
||||
INT16 sDesiredLevel;
|
||||
|
||||
// determine maximum horizontal limits
|
||||
sMaxLeft = min(ubDistance, (sSpot % MAXCOL));
|
||||
sMaxRight = min(ubDistance, MAXCOL - ((sSpot % MAXCOL) + 1));
|
||||
|
||||
// determine maximum vertical limits
|
||||
sMaxUp = min(ubDistance, (sSpot / MAXROW));
|
||||
sMaxDown = min(ubDistance, MAXROW - ((sSpot / MAXROW) + 1));
|
||||
|
||||
// count obstacles
|
||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||
{
|
||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||
{
|
||||
sCheckSpot = sSpot + sXOffset + (MAXCOL * sYOffset);
|
||||
|
||||
if (TileIsOutOfBounds(sCheckSpot))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InARoom(sSpot, &usRoom1) != InARoom(sCheckSpot, &usRoom2) || usRoom1 != usRoom2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sCountSpots++;
|
||||
|
||||
if (!IsLocationSittableExcludingPeople(sCheckSpot, bLevel))
|
||||
{
|
||||
sCountObstacles++;
|
||||
}
|
||||
|
||||
if (fGrass && IsLocationSittableExcludingPeople(sCheckSpot, bLevel))
|
||||
{
|
||||
pCurrent = gpWorldLevelData[sCheckSpot].pStructureHead;
|
||||
|
||||
if (bLevel > 0)
|
||||
sDesiredLevel = STRUCTURE_ON_ROOF;
|
||||
else
|
||||
sDesiredLevel = STRUCTURE_ON_GROUND;
|
||||
|
||||
if (pCurrent != NULL &&
|
||||
pCurrent->sCubeOffset == sDesiredLevel &&
|
||||
pCurrent->pDBStructureRef->pDBStructure->ubArmour == 4) // light vegetation
|
||||
{
|
||||
sCountObstacles++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sCountSpots > 0)
|
||||
return 100 * sCountObstacles / sCountSpots;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT16 DistanceToClosestActiveOpponent(SOLDIERTYPE *pSoldier, INT32 sSpot)
|
||||
{
|
||||
INT32 sGridNo;
|
||||
UINT32 uiLoop;
|
||||
INT8 bLevel;
|
||||
SOLDIERTYPE *pOpponent;
|
||||
INT16 sDistance, sClosestDistance = -1;
|
||||
|
||||
if (!pSoldier || TileIsOutOfBounds(sSpot))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// look through this man's personal & public opplists for opponents known
|
||||
for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++)
|
||||
{
|
||||
pOpponent = MercSlots[uiLoop];
|
||||
|
||||
// if this merc is inactive, at base, on assignment, or dead
|
||||
if (!pOpponent)
|
||||
{
|
||||
continue; // next merc
|
||||
}
|
||||
|
||||
if (!ValidOpponent(pSoldier, pOpponent))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pOpponent->stats.bLife < OKLIFE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if this opponent is unknown personally and publicly
|
||||
if (pSoldier->aiData.bOppList[pOpponent->ubID] == NOT_HEARD_OR_SEEN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// obtain opponent's location and level
|
||||
sGridNo = gsLastKnownOppLoc[pSoldier->ubID][pOpponent->ubID];
|
||||
bLevel = gbLastKnownOppLevel[pSoldier->ubID][pOpponent->ubID];
|
||||
|
||||
if (TileIsOutOfBounds(sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sDistance = PythSpacesAway(sSpot, sGridNo);
|
||||
|
||||
if (sClosestDistance < 0 ||
|
||||
sDistance < sClosestDistance)
|
||||
{
|
||||
sClosestDistance = sDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return sClosestDistance;
|
||||
}
|
||||
|
||||
BOOLEAN ValidOpponent(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pOpponent)
|
||||
{
|
||||
if (!pSoldier || !pOpponent)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pOpponent->bActive ||
|
||||
!pOpponent->bInSector ||
|
||||
pOpponent->stats.bLife == 0 ||
|
||||
CONSIDERED_NEUTRAL(pSoldier, pOpponent) ||
|
||||
pSoldier->bSide == pOpponent->bSide ||
|
||||
pSoldier->aiData.bAttitude == ATTACKSLAYONLY && pOpponent->ubProfile != SLAY ||
|
||||
(pOpponent->ubWhatKindOfMercAmI == MERC_TYPE__VEHICLE && GetNumberInVehicle(pOpponent->bVehicleID) == 0) ||
|
||||
gTacticalStatus.bBoxingState == BOXING && (pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) && !(pOpponent->flags.uiStatusFlags & SOLDIER_BOXER) ||
|
||||
pOpponent->ubBodyType == CROW)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN AnyCoverFromSpot( INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThreatLevel )
|
||||
{
|
||||
UINT8 ubDirection;
|
||||
|
||||
@@ -1084,7 +1084,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
|
||||
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: get out of water and gas"));
|
||||
|
||||
if (bInWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8))
|
||||
if (bInWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
@@ -1607,7 +1607,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
// WHEN IN GAS, GO TO NEAREST REACHABLE SPOT OF UNGASSED LAND
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if ( InGas(pSoldier, pSoldier->sGridNo) || DeepWater( pSoldier->sGridNo, pSoldier->pathing.bLevel ) || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8) )
|
||||
if (InGas(pSoldier, pSoldier->sGridNo) || DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel) || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE))
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
@@ -2582,7 +2582,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK)
|
||||
// WHEN IN GAS, GO TO NEAREST REACHABLE SPOT OF UNGASSED LAND
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (ubCanMove && (bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8)))
|
||||
if (ubCanMove && (bInGas || bInDeepWater || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)))
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
@@ -4719,7 +4719,7 @@ INT16 ubMinAPCost;
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// if soldier in water/gas has enough APs left to move at least 1 square
|
||||
if ( ( bInDeepWater || bInGas || FindBombNearby(pSoldier, pSoldier->sGridNo, DAY_VISION_RANGE/8) ) && ubCanMove)
|
||||
if (ubCanMove && (bInGas || bInDeepWater || FindBombNearby(pSoldier, pSoldier->sGridNo, BOMB_DETECTION_RANGE) || RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel)))
|
||||
{
|
||||
pSoldier->aiData.usActionData = FindNearestUngassedLand(pSoldier);
|
||||
|
||||
|
||||
+147
-47
@@ -423,7 +423,6 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
pHim->dYPos = dHisY; // and the 'y'
|
||||
}
|
||||
|
||||
|
||||
// these value should be < 1 million each
|
||||
iHisPosValue = bHisCTGT * Threat[uiThreatIndex].iValue * Threat[uiThreatIndex].iAPs;
|
||||
iMyPosValue = bMyCTGT * iMyThreat * iMyAPsLeft;
|
||||
@@ -438,7 +437,7 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
|
||||
sDist = PythSpacesAway(sMyGridNo, sHisGridNo);
|
||||
|
||||
if( sDist < DAY_VISION_RANGE / 2 )
|
||||
if (sDist < (INT32)(DAY_VISION_RANGE / 2))
|
||||
{
|
||||
ubCoverReduction = ubCoverReduction * 2 * sDist / DAY_VISION_RANGE;
|
||||
}
|
||||
@@ -888,6 +887,9 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
{
|
||||
iCurrentCoverValue -= abs(iCurrentCoverValue) / (8-ubDiff);
|
||||
}
|
||||
|
||||
// sevenfm: penalize locations near red smoke
|
||||
iCurrentCoverValue -= abs(iCurrentCoverValue) * RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel) / 100;
|
||||
}
|
||||
|
||||
#ifdef DEBUGCOVER
|
||||
@@ -1027,7 +1029,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
}
|
||||
|
||||
// sevenfm: avoid tiles near bombs
|
||||
if( FindBombNearby(pSoldier, sGridNo, DAY_VISION_RANGE / 8))
|
||||
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1046,6 +1048,15 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid moving into red smoke
|
||||
if (gGameExternalOptions.fAIBetterCover &&
|
||||
RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) &&
|
||||
!RedSmokeDanger(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
//DebugCover(pSoldier, String("moving into red smoke, skip"));
|
||||
continue;
|
||||
}
|
||||
|
||||
iPathCost = gubAIPathCosts[AI_PATHCOST_RADIUS + sXOffset][AI_PATHCOST_RADIUS + sYOffset];
|
||||
/*
|
||||
// water is OK, if the only good hiding place requires us to get wet, OK
|
||||
@@ -1134,6 +1145,9 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
{
|
||||
iCoverValue -= abs(iCoverValue) / (8-ubDiff);
|
||||
}
|
||||
|
||||
// sevenfm: penalize locations near red smoke
|
||||
iCoverValue -= abs(iCoverValue) * RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) / 100;
|
||||
}
|
||||
|
||||
if ( fNight && !( InARoom( sGridNo, NULL ) ) ) // ignore in buildings in case placed there
|
||||
@@ -1496,6 +1510,12 @@ INT32 FindSpotMaxDistFromOpponents(SOLDIERTYPE *pSoldier)
|
||||
continue;
|
||||
}
|
||||
|
||||
// sevenfm: avoid red smoke
|
||||
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// OK, this place shows potential. How useful is it as cover?
|
||||
//NumMessage("Promising seems gridno #",gridno);
|
||||
|
||||
@@ -1561,35 +1581,34 @@ INT32 FindSpotMaxDistFromOpponents(SOLDIERTYPE *pSoldier)
|
||||
|
||||
INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
INT32 sGridNo,sClosestLand = NOWHERE,sPathCost,sShortestPath = 1000;
|
||||
INT16 sMaxLeft,sMaxRight,sMaxUp,sMaxDown,sXOffset,sYOffset;
|
||||
INT32 sGridNo, sClosestLand = NOWHERE, sPathCost, sShortestPath = 1000;
|
||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||
INT32 iSearchRange;
|
||||
INT16 sDistance, sOriginalDistance;
|
||||
UINT16 usMovementMode = DetermineMovementMode(pSoldier, AI_ACTION_LEAVE_WATER_GAS);
|
||||
|
||||
//NameMessage(pSoldier,"looking for nearest reachable land");
|
||||
sOriginalDistance = DistanceToClosestActiveOpponent(pSoldier, pSoldier->sGridNo);
|
||||
|
||||
// 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...
|
||||
for (iSearchRange = 5; iSearchRange <= 25; iSearchRange += 5)
|
||||
for (iSearchRange = 5; iSearchRange <= 25; iSearchRange += 10)
|
||||
{
|
||||
//NumMessage("Trying iSearchRange = ", iSearchRange);
|
||||
|
||||
// determine maximum horizontal limits
|
||||
sMaxLeft = min(iSearchRange,(pSoldier->sGridNo % MAXCOL));
|
||||
sMaxLeft = min(iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
||||
//NumMessage("sMaxLeft = ",sMaxLeft);
|
||||
sMaxRight = min(iSearchRange,MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||
sMaxRight = min(iSearchRange, MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||
//NumMessage("sMaxRight = ",sMaxRight);
|
||||
|
||||
// determine maximum vertical limits
|
||||
sMaxUp = min(iSearchRange,(pSoldier->sGridNo / MAXROW));
|
||||
sMaxUp = min(iSearchRange, (pSoldier->sGridNo / MAXROW));
|
||||
//NumMessage("sMaxUp = ",sMaxUp);
|
||||
sMaxDown = min(iSearchRange,MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
|
||||
sMaxDown = min(iSearchRange, MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
|
||||
//NumMessage("sMaxDown = ",sMaxDown);
|
||||
|
||||
// Call FindBestPath to set flags in all locations that we can
|
||||
// walk into within range. We have to set some things up first...
|
||||
|
||||
// set the distance limit of the square region
|
||||
gubNPCDistLimit = (UINT8) iSearchRange;
|
||||
// walk into within range. We have to set some things up first...
|
||||
|
||||
// reset the "reachable" flags in the region we're looking at
|
||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||
@@ -1597,7 +1616,7 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||
{
|
||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
||||
if (!(sGridNo >= 0 && sGridNo < WORLD_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1606,7 +1625,11 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
}
|
||||
|
||||
FindBestPath( pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, DetermineMovementMode( pSoldier, AI_ACTION_LEAVE_WATER_GAS ), COPYREACHABLE, 0 );//dnl ch50 071009
|
||||
gubNPCAPBudget = pSoldier->bActionPoints;
|
||||
gubNPCDistLimit = (UINT8)iSearchRange;
|
||||
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0); //dnl ch50 071009
|
||||
gubNPCAPBudget = 0;
|
||||
gubNPCDistLimit = 0;
|
||||
|
||||
// Turn off the "reachable" flag for his current location
|
||||
// so we don't consider it
|
||||
@@ -1620,7 +1643,7 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
// calculate the next potential gridno
|
||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
//NumMessage("Testing gridno #",gridno);
|
||||
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
||||
if (!(sGridNo >= 0 && sGridNo < WORLD_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1631,7 +1654,31 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
|
||||
// ignore blacklisted spot
|
||||
if ( sGridNo == pSoldier->pathing.sBlackList )
|
||||
if (sGridNo == pSoldier->pathing.sBlackList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// sevenfm: check for gas
|
||||
if (InGas(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for deep water
|
||||
if (DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for bombs nearby
|
||||
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for red smoke
|
||||
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1642,16 +1689,39 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for red smoke
|
||||
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// CJC: here, unfortunately, we must calculate a path so we have an AP cost
|
||||
|
||||
// obviously, we're looking for LAND, so water is out!
|
||||
sPathCost = LegalNPCDestination(pSoldier,sGridNo,ENSURE_PATH_COST,NOWATER,0);
|
||||
//sPathCost = LegalNPCDestination(pSoldier,sGridNo,ENSURE_PATH_COST,NOWATER,0);
|
||||
|
||||
if (!sPathCost)
|
||||
if (!LegalNPCDestination(pSoldier, sGridNo, IGNORE_PATH, NOWATER, 0))
|
||||
{
|
||||
continue; // skip on to the next potential grid
|
||||
}
|
||||
|
||||
sPathCost = PlotPath(pSoldier, sGridNo, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, pSoldier->bReverse, 0);
|
||||
|
||||
// check if spot is reachable
|
||||
if(sPathCost == 0)
|
||||
{
|
||||
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 (sPathCost < sShortestPath)
|
||||
{
|
||||
@@ -1674,49 +1744,47 @@ INT32 FindNearestUngassedLand(SOLDIERTYPE *pSoldier)
|
||||
return(sClosestLand);
|
||||
}
|
||||
|
||||
INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
|
||||
INT32 FindNearbyDarkerSpot(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
INT32 sGridNo, sClosestSpot = NOWHERE, sPathCost;
|
||||
INT32 iSpotValue, iBestSpotValue = 1000;
|
||||
INT16 sMaxLeft,sMaxRight,sMaxUp,sMaxDown,sXOffset,sYOffset;
|
||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||
INT32 iSearchRange;
|
||||
INT8 bLightLevel, bCurrLightLevel, bLightDiff;
|
||||
INT32 iRoamRange;
|
||||
INT32 sOrigin;
|
||||
UINT16 usMovementMode = DetermineMovementMode(pSoldier, AI_ACTION_LEAVE_WATER_GAS);
|
||||
|
||||
bCurrLightLevel = LightTrueLevel( pSoldier->sGridNo, pSoldier->pathing.bLevel );
|
||||
bCurrLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel);
|
||||
|
||||
iRoamRange = RoamingRange( pSoldier, &sOrigin );
|
||||
iRoamRange = RoamingRange(pSoldier, &sOrigin);
|
||||
|
||||
// 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...
|
||||
for (iSearchRange = 5; iSearchRange <= 15; iSearchRange += 5)
|
||||
{
|
||||
// determine maximum horizontal limits
|
||||
sMaxLeft = min(iSearchRange,(pSoldier->sGridNo % MAXCOL));
|
||||
sMaxLeft = min(iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
||||
//NumMessage("sMaxLeft = ",sMaxLeft);
|
||||
sMaxRight = min(iSearchRange,MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||
sMaxRight = min(iSearchRange, MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||
//NumMessage("sMaxRight = ",sMaxRight);
|
||||
|
||||
// determine maximum vertical limits
|
||||
sMaxUp = min(iSearchRange,(pSoldier->sGridNo / MAXROW));
|
||||
sMaxUp = min(iSearchRange, (pSoldier->sGridNo / MAXROW));
|
||||
//NumMessage("sMaxUp = ",sMaxUp);
|
||||
sMaxDown = min(iSearchRange,MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
|
||||
sMaxDown = min(iSearchRange, MAXROW - ((pSoldier->sGridNo / MAXROW) + 1));
|
||||
//NumMessage("sMaxDown = ",sMaxDown);
|
||||
|
||||
// Call FindBestPath to set flags in all locations that we can
|
||||
// walk into within range. We have to set some things up first...
|
||||
|
||||
// set the distance limit of the square region
|
||||
gubNPCDistLimit = (UINT8) iSearchRange;
|
||||
|
||||
// reset the "reachable" flags in the region we're looking at
|
||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||
{
|
||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||
{
|
||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
||||
if (!(sGridNo >= 0 && sGridNo < WORLD_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1725,7 +1793,11 @@ INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
|
||||
}
|
||||
}
|
||||
|
||||
FindBestPath( pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, DetermineMovementMode( pSoldier, AI_ACTION_LEAVE_WATER_GAS ), COPYREACHABLE, 0 );//dnl ch50 071009
|
||||
gubNPCAPBudget = pSoldier->bActionPoints;
|
||||
gubNPCDistLimit = (UINT8)iSearchRange;
|
||||
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0); //dnl ch50 071009
|
||||
gubNPCAPBudget = 0;
|
||||
gubNPCDistLimit = 0;
|
||||
|
||||
// Turn off the "reachable" flag for his current location
|
||||
// so we don't consider it
|
||||
@@ -1739,7 +1811,7 @@ INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
|
||||
// calculate the next potential gridno
|
||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
//NumMessage("Testing gridno #",gridno);
|
||||
if ( !(sGridNo >=0 && sGridNo < WORLD_MAX) )
|
||||
if (!(sGridNo >= 0 && sGridNo < WORLD_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1750,7 +1822,18 @@ INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
|
||||
}
|
||||
|
||||
// ignore blacklisted spot
|
||||
if ( sGridNo == pSoldier->pathing.sBlackList )
|
||||
if (sGridNo == pSoldier->pathing.sBlackList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// require this character to stay within their roam range
|
||||
if (PythSpacesAway(sOrigin, sGridNo) > iRoamRange)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1761,29 +1844,35 @@ INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
|
||||
continue;
|
||||
}
|
||||
|
||||
// require this character to stay within their roam range
|
||||
if ( PythSpacesAway( sOrigin, sGridNo ) > iRoamRange )
|
||||
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// screen out anything brighter than our current best spot
|
||||
bLightLevel = LightTrueLevel( sGridNo, pSoldier->pathing.bLevel );
|
||||
bLightLevel = LightTrueLevel(sGridNo, pSoldier->pathing.bLevel);
|
||||
|
||||
//bLightDiff = gbLightSighting[0][ bCurrLightLevel ] - gbLightSighting[0][ bLightLevel ];
|
||||
bLightDiff = gGameExternalOptions.ubBrightnessVisionMod[ bCurrLightLevel ] - gGameExternalOptions.ubBrightnessVisionMod[ bLightLevel ];
|
||||
bLightDiff = gGameExternalOptions.ubBrightnessVisionMod[bCurrLightLevel] - gGameExternalOptions.ubBrightnessVisionMod[bLightLevel];
|
||||
// if the spot is darker than our current location, then bLightDiff > 0
|
||||
// plus ignore differences of just 1 light level
|
||||
if ( bLightDiff <= 1 )
|
||||
if (bLightDiff <= 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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,NOWATER,0);
|
||||
if (!LegalNPCDestination(pSoldier, sGridNo, IGNORE_PATH, NOWATER, 0))
|
||||
{
|
||||
continue; // skip on to the next potential grid
|
||||
}
|
||||
|
||||
if (!sPathCost)
|
||||
sPathCost = PlotPath(pSoldier, sGridNo, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, pSoldier->bReverse, 0);
|
||||
|
||||
// check if spot is reachable
|
||||
if (sPathCost == 0)
|
||||
{
|
||||
continue; // skip on to the next potential grid
|
||||
}
|
||||
@@ -1791,7 +1880,7 @@ INT32 FindNearbyDarkerSpot( SOLDIERTYPE *pSoldier )
|
||||
// decrease the "cost" of the spot by the amount of light/darkness
|
||||
iSpotValue = sPathCost * 2 - bLightDiff;
|
||||
|
||||
if ( iSpotValue < iBestSpotValue )
|
||||
if (iSpotValue < iBestSpotValue)
|
||||
{
|
||||
// remember it instead
|
||||
iBestSpotValue = iSpotValue;
|
||||
@@ -2676,7 +2765,8 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
||||
}
|
||||
|
||||
// sevenfm: don't go into deep water for flanking
|
||||
if( DeepWater( sGridNo, pSoldier->pathing.bLevel ) )
|
||||
if (DeepWater(sGridNo, pSoldier->pathing.bLevel) &&
|
||||
!DeepWater(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -2695,14 +2785,24 @@ INT32 FindFlankingSpot(SOLDIERTYPE *pSoldier, INT32 sPos, INT8 bAction )
|
||||
continue;
|
||||
}
|
||||
|
||||
// sevenfm: skip buildings if not in building already, because soldiers often run into buildings and stop flanking
|
||||
if (InARoom(sGridNo, NULL) && !InARoom(pSoldier->sGridNo, NULL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// sevenfm: penalize locations near fresh corpses
|
||||
if( GetNearestRottingCorpseAIWarning( sGridNo ) > 0 )
|
||||
{
|
||||
sTempDist = sTempDist / 2;
|
||||
}
|
||||
|
||||
if (FindBombNearby(pSoldier, sGridNo, BOMB_DETECTION_RANGE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// sevenfm: skip buildings if not in building already, because soldiers often run into buildings and stop flanking
|
||||
if( InARoom( sGridNo, NULL ) && !InARoom(pSoldier->sGridNo, NULL) )
|
||||
if (RedSmokeDanger(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -297,6 +297,12 @@ BOOLEAN ProneSightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
|
||||
BOOLEAN SightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
|
||||
|
||||
BOOLEAN FindBombNearby( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubDistance );
|
||||
UINT8 RedSmokeDanger(INT32 sGridNo, INT8 bLevel);
|
||||
BOOLEAN CheckArtilleryStrike(void);
|
||||
BOOLEAN CheckRoof(INT32 sGridNo);
|
||||
UINT8 TerrainDensity(INT32 sSpot, INT8 bLevel, UINT8 ubDistance, BOOLEAN fGrass);
|
||||
INT16 DistanceToClosestActiveOpponent(SOLDIERTYPE *pSoldier, INT32 sSpot);
|
||||
BOOLEAN ValidOpponent(SOLDIERTYPE* pSoldier, SOLDIERTYPE* pOpponent);
|
||||
|
||||
BOOLEAN AnyCoverFromSpot( INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThreatLevel );
|
||||
UINT8 CountSeenEnemiesLastTurn( SOLDIERTYPE *pSoldier );
|
||||
@@ -320,5 +326,6 @@ BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier);
|
||||
|
||||
// sevenfm: distance for tactical AI checks, roughly equal to normal day vision range
|
||||
#define TACTICAL_RANGE (gGameExternalOptions.ubStraightSightRange * STRAIGHT_RATIO * 2)
|
||||
#define BOMB_DETECTION_RANGE (TACTICAL_RANGE / 4)
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user