mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
New option AI_DECISION_INFO enables extended logging for AI decisions.
Moved zombie AI into separate file ZombieDecideAction.cpp New zombie AI: - simplified code - advancing using cover - if zombie cannot reach any opponent, he tries to hide - if zombie cannot reach opponent and cannot hide and he is under fire, he will retreat, seeking cover away from known opponents - if zombie doesn't know enemy location, he will try to run to closest friend who knows enemy location - new zombie AI has extended AI logging More water splash sounds (Data\Sounds\Misc\Splash1.ogg .. SplashN.ogg). CalcCoverValue: - allow moving into shallow water if it provides better position - special calculations for zombies: zombie is very dangerous at close range - if soldier has no gun, use different calculation based on distance instead of CTGT FindBestNearbyCover: zombies only choose spots that provide sight cover. Added functions for extended AI log. ClosestReachableDisturbance: - if soldier is zombie and he cannot climb, skip location - zombies do not attack vehicles - improved check to avoid choosing dying opponents EstimatePathCostToLocation: return 0 if checking for zombie which cannot climb and path needs climbing. RoamingRange: always max roaming range for zombies. SightCoverAtSpot, ProneSightCoverAtSpot: - improved max sight range calculation - added option for unlimited sight range check New AI functions: - AIDirection - AICheckIsSniper - AICheckIsMarksman - AICheckIsMedic - AICheckIsMortarOperator - AICheckIsGLOperator - AICheckIsOfficer - AICheckIsCommander - AICheckIsMachinegunner - AIGunInHandScoped - AIGunScoped - AIGunRange - AIGunClass - AIGunType - AIGunDeadliness - AIGunAmmo - AIGunAutofireCapable - FindObstacleNearSpot - InSmoke - CorpseWarning - CorpseEnemyTeam - CorpseMilitiaTeam - AICheckUnderground - AnyCoverAtSpot - AICheckHasWeaponOfType - AICheckHasGun - AICheckShortWeaponRange GetCorpseAtGridNo: additional check for valid gridno. More zombie raise sounds (Data\Sounds\Misc\ZombieRaise1.ogg .. ZombieRaiseN.ogg). GetCorpseRotFactor: improved code to return FLOAT value between 0 and 1. New debug topic id TOPIC_DECISIONS for logging AI decisions. git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8760 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -2295,6 +2295,7 @@ void LoadGameExternalOptions()
|
||||
gGameExternalOptions.fAITacticalRetreat = iniReader.ReadBoolean("Tactical AI Settings", "AI_TACTICAL_RETREAT", FALSE);
|
||||
gGameExternalOptions.fAIMovementMode = iniReader.ReadBoolean("Tactical AI Settings", "AI_MOVEMENT_MODE", TRUE);
|
||||
gGameExternalOptions.fAIPathTweaks = iniReader.ReadBoolean("Tactical AI Settings", "AI_PATH_TWEAKS", TRUE);
|
||||
gGameExternalOptions.fAIDecisionInfo = iniReader.ReadBoolean("Tactical AI Settings", "AI_DECISION_INFO", false, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1555,6 +1555,7 @@ typedef struct
|
||||
BOOLEAN fAITacticalRetreat;
|
||||
BOOLEAN fAIMovementMode;
|
||||
BOOLEAN fAIPathTweaks;
|
||||
BOOLEAN fAIDecisionInfo;
|
||||
|
||||
} GAME_EXTERNAL_OPTIONS;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
const unsigned INVALID_TOPIC = 0xffff;
|
||||
|
||||
const unsigned TOPIC_DECISIONS = 25;
|
||||
const unsigned TOPIC_MEMORY_MANAGER = 24;
|
||||
const unsigned TOPIC_FILE_MANAGER = 23;
|
||||
const unsigned TOPIC_DATABASE_MANAGER = 22;
|
||||
|
||||
@@ -988,6 +988,9 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, UINT8 ub
|
||||
if ( pSoldier->usSoldierFlagMask & SOLDIER_COVERT_TEMPORARY_OVERT && pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] > 0 )
|
||||
pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] = max( 0, (INT16)(pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_COVERTOPS_TEMPORARYOVERT_APS] - sAPCost) );
|
||||
|
||||
// sevenfm: indicate in realtime that soldier spent some action point this turn
|
||||
pSoldier->usSoldierFlagMask2 |= SOLDIER_SPENT_AP;
|
||||
|
||||
pSoldier->StopChatting();
|
||||
}
|
||||
|
||||
|
||||
@@ -60,10 +60,6 @@
|
||||
class OBJECTTYPE;
|
||||
class SOLDIERTYPE;
|
||||
|
||||
|
||||
#define CORPSE_WARNING_MAX 5
|
||||
#define CORPSE_WARNING_DIST 5
|
||||
|
||||
#define CORPSE_INDEX_OFFSET 10000
|
||||
|
||||
// Flugente: these are ini values now
|
||||
@@ -501,7 +497,7 @@ INT32 AddRottingCorpse( ROTTING_CORPSE_DEFINITION *pCorpseDef )
|
||||
|
||||
uiDirectionUseFlag = ANITILE_USE_DIRECTION_FOR_START_FRAME;
|
||||
|
||||
// If we are a soecial type...
|
||||
// If we are a special type...
|
||||
switch( pCorpseDef->ubType )
|
||||
{
|
||||
case SMERC_FALL:
|
||||
@@ -527,7 +523,7 @@ INT32 AddRottingCorpse( ROTTING_CORPSE_DEFINITION *pCorpseDef )
|
||||
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) )
|
||||
{
|
||||
// OK, AS WE ADD, CHECK FOR TOD AND DECAY APPROPRIATELY
|
||||
if ( ((GetWorldTotalMin( ) - pCorpse->def.uiTimeOfDeath) > gGameExternalOptions.usCorpseDelayUntilRotting) && (pCorpse->def.ubType < ROTTING_STAGE2) )
|
||||
if ( ((GetWorldTotalMin( ) - pCorpse->def.uiTimeOfDeath) >= gGameExternalOptions.usCorpseDelayUntilRotting) && (pCorpse->def.ubType < ROTTING_STAGE2) )
|
||||
{
|
||||
if ( pCorpse->def.ubType <= FMERC_FALLF )
|
||||
{
|
||||
@@ -1693,17 +1689,17 @@ INT32 FindNearestAvailableGridNoForCorpse( ROTTING_CORPSE_DEFINITION *pDef, INT8
|
||||
INT16 sTop, sBottom;
|
||||
INT16 sLeft, sRight;
|
||||
INT16 cnt1, cnt2, cnt3;
|
||||
INT32 sGridNo;
|
||||
INT32 uiRange, uiLowestRange = 999999;
|
||||
INT32 sLowestGridNo=0;
|
||||
INT32 leftmost;
|
||||
INT32 sGridNo;
|
||||
INT32 uiRange, uiLowestRange = 999999;
|
||||
INT32 sLowestGridNo=0;
|
||||
INT32 leftmost;
|
||||
BOOLEAN fFound = FALSE;
|
||||
SOLDIERTYPE soldier;
|
||||
INT16 ubSaveNPCAPBudget;
|
||||
UINT8 ubSaveNPCDistLimit;
|
||||
INT16 ubSaveNPCAPBudget;
|
||||
UINT8 ubSaveNPCDistLimit;
|
||||
STRUCTURE_FILE_REF * pStructureFileRef = NULL;
|
||||
CHAR8 zFilename[150];
|
||||
UINT8 ubBestDirection=0;
|
||||
CHAR8 zFilename[150];
|
||||
UINT8 ubBestDirection=0;
|
||||
BOOLEAN fSetDirection = FALSE;
|
||||
|
||||
cnt3 = 0;
|
||||
@@ -1752,8 +1748,6 @@ INT32 FindNearestAvailableGridNoForCorpse( ROTTING_CORPSE_DEFINITION *pDef, INT8
|
||||
//(use the fake soldier and the pathing settings)
|
||||
FindBestPath( &soldier, GRIDSIZE, 0, WALKING, COPYREACHABLE, 0 );//dnl ch50 071009
|
||||
|
||||
uiLowestRange = 999999;
|
||||
|
||||
for( cnt1 = sBottom; cnt1 <= sTop; cnt1++ )
|
||||
{
|
||||
leftmost = ( ( sSweetGridNo + ( WORLD_COLS * cnt1 ) )/ WORLD_COLS ) * WORLD_COLS;
|
||||
@@ -1847,12 +1841,15 @@ ROTTING_CORPSE *GetCorpseAtGridNo( INT32 sGridNo, INT8 bLevel )
|
||||
// Get base....
|
||||
pBaseStructure = FindBaseStructure( pStructure );
|
||||
|
||||
// Find base gridno...
|
||||
sBaseGridNo = pBaseStructure->sGridNo;
|
||||
|
||||
if ( pBaseStructure != NULL )
|
||||
{
|
||||
return(FindCorpseBasedOnStructure( sBaseGridNo, bLevel, pBaseStructure ));
|
||||
// Find base gridno...
|
||||
sBaseGridNo = pBaseStructure->sGridNo;
|
||||
|
||||
if (!TileIsOutOfBounds(sBaseGridNo))
|
||||
{
|
||||
return(FindCorpseBasedOnStructure(sBaseGridNo, bLevel, pBaseStructure));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2692,6 +2689,7 @@ std::vector<INT16> GetCorpseIDsNearGridNo( INT32 sGridNo, INT8 bLevel, INT8 sRad
|
||||
}
|
||||
|
||||
extern UNDERGROUND_SECTORINFO* FindUnderGroundSector( INT16 sMapX, INT16 sMapY, UINT8 bMapZ );
|
||||
INT16 gsZombieRaiseSoundNum = -1;
|
||||
|
||||
// Flugente Zombies: resurrect zombies
|
||||
void RaiseZombies( void )
|
||||
@@ -2801,8 +2799,32 @@ void RaiseZombies( void )
|
||||
#ifdef JA2TESTVERSION
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"A wave of zombies is created");
|
||||
#endif
|
||||
// Play sound
|
||||
PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
|
||||
CHAR8 zFilename[512];
|
||||
// prepare zombie raise sound
|
||||
if (gsZombieRaiseSoundNum < 0)
|
||||
{
|
||||
gsZombieRaiseSoundNum = 0;
|
||||
do
|
||||
{
|
||||
gsZombieRaiseSoundNum++;
|
||||
sprintf(zFilename, "Sounds\\Misc\\ZombieRaise%d.ogg", gsZombieRaiseSoundNum);
|
||||
} while (FileExists(zFilename));
|
||||
gsZombieRaiseSoundNum--;
|
||||
}
|
||||
if (gsZombieRaiseSoundNum > 0)
|
||||
{
|
||||
sprintf(zFilename, "Sounds\\Misc\\ZombieRaise%d.ogg", Random(gsZombieRaiseSoundNum) + 1);
|
||||
if (FileExists(zFilename))
|
||||
{
|
||||
//PlayJA2SampleFromFile(zFilename, RATE_11025, SoundVolume(MIDVOLUME, this->sGridNo), 1, SoundDir(this->sGridNo));
|
||||
PlayJA2SampleFromFile(zFilename, RATE_11025, MIDVOLUME, 1, MIDDLEPAN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play default sound
|
||||
PlayJA2SampleFromFile("Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN);
|
||||
}
|
||||
|
||||
UseCreatureMusic(TRUE); // Madd: music when zombies rise
|
||||
#ifdef NEWMUSIC
|
||||
@@ -3251,5 +3273,5 @@ FLOAT GetCorpseRotFactor( ROTTING_CORPSE* pCorpse )
|
||||
if ( pCorpse->def.ubType == ROTTING_STAGE2 )
|
||||
return 1.0f;
|
||||
|
||||
return (GetWorldTotalMin( ) - pCorpse->def.uiTimeOfDeath) / gGameExternalOptions.usCorpseDelayUntilRotting;
|
||||
return (FLOAT)(min(gGameExternalOptions.usCorpseDelayUntilRotting, GetWorldTotalMin() - pCorpse->def.uiTimeOfDeath)) / gGameExternalOptions.usCorpseDelayUntilRotting;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "tile animation.h"
|
||||
|
||||
#define NUM_CORPSE_SHADES 17
|
||||
#define CORPSE_WARNING_MAX 5
|
||||
#define CORPSE_WARNING_DIST 5
|
||||
|
||||
enum RottingCorpseDefines
|
||||
{
|
||||
|
||||
@@ -16522,6 +16522,16 @@ BOOLEAN SOLDIERTYPE::IsAssassin( )
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN SOLDIERTYPE::CheckInitialAP(void)
|
||||
{
|
||||
if (this->bActionPoints < this->bInitialActionPoints || this->usSoldierFlagMask2 & SOLDIER_SPENT_AP)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT8 SOLDIERTYPE::GetMultiTurnAction( )
|
||||
{
|
||||
return usMultiTurnAction;
|
||||
@@ -17679,7 +17689,7 @@ void SOLDIERTYPE::SoldierPropertyUpkeep( )
|
||||
{
|
||||
// these effects last only one turn
|
||||
this->usSoldierFlagMask &= ~(SOLDIER_AIRDROP_TURN | SOLDIER_ASSAULT_BONUS | SOLDIER_RAISED_REDALERT);
|
||||
this->usSoldierFlagMask2 &= ~SOLDIER_CONCEALINSERTION;
|
||||
this->usSoldierFlagMask2 &= ~(SOLDIER_CONCEALINSERTION | SOLDIER_SPENT_AP);
|
||||
|
||||
// this looks bizarre, but is required
|
||||
if ( this->usSoldierFlagMask2 & SOLDIER_CONCEALINSERTION_DISCOVERED )
|
||||
|
||||
@@ -425,6 +425,7 @@ enum
|
||||
#define SOLDIER_SURGERY_BOOSTED 0x00040000 // we are a boosted performing surgery (e.g. by using up a blood bag)
|
||||
|
||||
#define SOLDIER_DRAG_SOUND 0x00080000 // played sound when started dragging
|
||||
#define SOLDIER_SPENT_AP 0x00100000 // soldier has spent some AP this turn (including realtime)
|
||||
|
||||
#define SOLDIER_INTERROGATE_ALL 0x000001F8 // all interrogation flags
|
||||
// ----------------------------------------------------------------
|
||||
@@ -1854,6 +1855,9 @@ public:
|
||||
// Flugente: are we an assassin?
|
||||
BOOLEAN IsAssassin();
|
||||
|
||||
// sevenfm: service functions
|
||||
BOOLEAN CheckInitialAP(void);
|
||||
|
||||
// Flugente: multi-turn actions
|
||||
UINT8 GetMultiTurnAction();
|
||||
void StartMultiTurnAction( UINT8 usActionType, INT32 asGridNo );
|
||||
|
||||
@@ -232,6 +232,7 @@ INT32 GoAsFarAsPossibleTowards(SOLDIERTYPE *pSoldier, INT32 sDesGrid, INT8 bActi
|
||||
|
||||
INT8 HeadForTheStairCase( SOLDIERTYPE * pSoldier );
|
||||
|
||||
BOOLEAN InSmoke(INT32 sGridNo, INT8 bLevel);
|
||||
BOOLEAN InGas( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
BOOLEAN InGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
BOOLEAN InWaterGasOrSmoke( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
|
||||
@@ -134,6 +134,191 @@ void DebugAI( STR szOutput )
|
||||
#endif
|
||||
}
|
||||
|
||||
STR szAction[] = {
|
||||
"AI_ACTION_NONE",
|
||||
|
||||
"AI_ACTION_RANDOM_PATROL",
|
||||
"AI_ACTION_SEEK_FRIEND",
|
||||
"AI_ACTION_SEEK_OPPONENT",
|
||||
"AI_ACTION_TAKE_COVER",
|
||||
"AI_ACTION_GET_CLOSER",
|
||||
|
||||
"AI_ACTION_POINT_PATROL",
|
||||
"AI_ACTION_LEAVE_WATER_GAS",
|
||||
"AI_ACTION_SEEK_NOISE",
|
||||
"AI_ACTION_ESCORTED_MOVE",
|
||||
"AI_ACTION_RUN_AWAY",
|
||||
|
||||
"AI_ACTION_KNIFE_MOVE",
|
||||
"AI_ACTION_APPROACH_MERC",
|
||||
"AI_ACTION_TRACK",
|
||||
"AI_ACTION_EAT",
|
||||
"AI_ACTION_PICKUP_ITEM",
|
||||
|
||||
"AI_ACTION_SCHEDULE_MOVE",
|
||||
"AI_ACTION_WALK",
|
||||
"AI_ACTION_RUN",
|
||||
"AI_ACTION_WITHDRAW",
|
||||
"AI_ACTION_FLANK_LEFT",
|
||||
"AI_ACTION_FLANK_RIGHT",
|
||||
"AI_ACTION_MOVE_TO_CLIMB",
|
||||
|
||||
"AI_ACTION_CHANGE_FACING",
|
||||
|
||||
"AI_ACTION_CHANGE_STANCE",
|
||||
|
||||
"AI_ACTION_YELLOW_ALERT",
|
||||
"AI_ACTION_RED_ALERT",
|
||||
"AI_ACTION_CREATURE_CALL",
|
||||
"AI_ACTION_PULL_TRIGGER",
|
||||
|
||||
"AI_ACTION_USE_DETONATOR",
|
||||
"AI_ACTION_FIRE_GUN",
|
||||
"AI_ACTION_TOSS_PROJECTILE",
|
||||
"AI_ACTION_KNIFE_STAB",
|
||||
"AI_ACTION_THROW_KNIFE",
|
||||
|
||||
"AI_ACTION_GIVE_AID",
|
||||
"AI_ACTION_WAIT",
|
||||
"AI_ACTION_PENDING_ACTION",
|
||||
"AI_ACTION_DROP_ITEM",
|
||||
"AI_ACTION_COWER",
|
||||
|
||||
"AI_ACTION_STOP_COWERING",
|
||||
"AI_ACTION_OPEN_OR_CLOSE_DOOR",
|
||||
"AI_ACTION_UNLOCK_DOOR",
|
||||
"AI_ACTION_LOCK_DOOR",
|
||||
"AI_ACTION_LOWER_GUN",
|
||||
|
||||
"AI_ACTION_ABSOLUTELY_NONE",
|
||||
"AI_ACTION_CLIMB_ROOF",
|
||||
"AI_ACTION_END_TURN",
|
||||
"AI_ACTION_END_COWER_AND_MOVE",
|
||||
"AI_ACTION_TRAVERSE_DOWN",
|
||||
"AI_ACTION_OFFER_SURRENDER",
|
||||
"AI_ACTION_RAISE_GUN",
|
||||
"AI_ACTION_STEAL_MOVE",
|
||||
|
||||
"AI_ACTION_RELOAD_GUN",
|
||||
|
||||
"AI_ACTION_JUMP_WINDOW",
|
||||
"AI_ACTION_FREE_PRISONER",
|
||||
"AI_ACTION_USE_SKILL",
|
||||
"AI_ACTION_DOCTOR",
|
||||
"AI_ACTION_DOCTOR_SELF",
|
||||
"AI_ACTION_SELFDETONATE",
|
||||
"AI_ACTION_STOP_MEDIC"
|
||||
};
|
||||
|
||||
// sevenfm
|
||||
UINT32 guiAIStartCounter = 0, guiAILastCounter = 0;
|
||||
//UINT8 gubAISelectedSoldier = NOBODY;
|
||||
|
||||
void DebugAI( INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, INT8 bAction )
|
||||
{
|
||||
FILE* DebugFile;
|
||||
CHAR8 msg[1024];
|
||||
CHAR8 buf[1024];
|
||||
|
||||
if (!gGameExternalOptions.fAIDecisionInfo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memset(buf, 0, 1024 * sizeof(char));
|
||||
|
||||
/*if (bMsgType == AI_MSG_TOPIC && !gGameExternalOptions.fDecisionTopicInfo)
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
|
||||
if (bMsgType == AI_MSG_START)
|
||||
{
|
||||
guiAIStartCounter = GetJA2Clock();
|
||||
guiAILastCounter = GetJA2Clock();
|
||||
}
|
||||
|
||||
sprintf(msg, "");
|
||||
|
||||
if (pSoldier)
|
||||
{
|
||||
sprintf(buf, "[%d] (%d)", pSoldier->ubID, pSoldier->sGridNo);
|
||||
strcat(msg, buf);
|
||||
|
||||
if (pSoldier->ubProfile != NO_PROFILE)
|
||||
{
|
||||
wcstombs(buf, pSoldier->GetName(), 1024 - 1);
|
||||
strcat(msg, " ");
|
||||
strcat(msg, buf);
|
||||
}
|
||||
}
|
||||
|
||||
strcat(msg, " ");
|
||||
|
||||
if (bAction >= 0)
|
||||
{
|
||||
sprintf(buf, " (total %d ms)", GetJA2Clock() - guiAIStartCounter);
|
||||
strcat(msg, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(buf, " (%d ms)", GetJA2Clock() - guiAILastCounter);
|
||||
strcat(msg, buf);
|
||||
}
|
||||
|
||||
if (bAction >= AI_ACTION_NONE && bAction <= AI_ACTION_LAST)
|
||||
{
|
||||
strcat(msg, " ");
|
||||
strcat(msg, szAction[bAction]);
|
||||
|
||||
if (pSoldier)
|
||||
{
|
||||
sprintf(buf, " %d", pSoldier->aiData.usActionData);
|
||||
strcat(msg, buf);
|
||||
}
|
||||
|
||||
if (pSoldier && pSoldier->aiData.bNextAction != AI_ACTION_NONE)
|
||||
{
|
||||
strcat(msg, " ");
|
||||
strcat(msg, szAction[pSoldier->aiData.bNextAction]);
|
||||
|
||||
sprintf(buf, " %d", pSoldier->aiData.usNextActionData);
|
||||
strcat(msg, buf);
|
||||
}
|
||||
}
|
||||
|
||||
strcat(msg, " ");
|
||||
strcat(msg, szOutput);
|
||||
|
||||
guiAILastCounter = GetJA2Clock();
|
||||
|
||||
DebugMsg(TOPIC_DECISIONS, DBG_LEVEL_3, szOutput);
|
||||
|
||||
if ((DebugFile = fopen("Logs\\AI_Decisions.txt", "a+t")) != NULL)
|
||||
{
|
||||
if (bMsgType == AI_MSG_START)
|
||||
{
|
||||
fputs("\n", DebugFile);
|
||||
}
|
||||
fputs(msg, DebugFile);
|
||||
fputs("\n", DebugFile);
|
||||
fclose(DebugFile);
|
||||
}
|
||||
|
||||
// also log to individual file for selected soldier
|
||||
sprintf(buf, "Logs\\AI_Decisions [%d].txt", pSoldier->ubID);
|
||||
if ((DebugFile = fopen(buf, "a+t")) != NULL)
|
||||
{
|
||||
if (bMsgType == AI_MSG_START)
|
||||
{
|
||||
fputs("\n", DebugFile);
|
||||
}
|
||||
fputs(msg, DebugFile);
|
||||
fputs("\n", DebugFile);
|
||||
fclose(DebugFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN InitAI( void )
|
||||
{
|
||||
@@ -164,6 +349,17 @@ BOOLEAN InitAI( void )
|
||||
}
|
||||
#endif
|
||||
|
||||
// sevenfm: Clear the AI debug txt file to prevent it from getting huge
|
||||
remove("Logs\\AI_Decisions.txt");
|
||||
|
||||
// remove all individual files
|
||||
CHAR8 buf[1024];
|
||||
for (UINT8 cnt = 0; cnt < TOTAL_SOLDIERS; cnt++)
|
||||
{
|
||||
sprintf(buf, "Logs\\AI_Decisions [%d].txt", cnt);
|
||||
remove(buf);
|
||||
}
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
|
||||
+813
-127
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,11 @@
|
||||
class OBJECTTYPE;
|
||||
class SOLDIERTYPE;
|
||||
|
||||
extern STR8 gStr8AlertStatus[];
|
||||
extern STR8 gStr8Attitude[];
|
||||
extern STR8 gStr8Orders[];
|
||||
extern STR8 gStr8Team[];
|
||||
extern STR8 gStr8Class[];
|
||||
|
||||
extern INT8 STRAIGHT; //lal
|
||||
|
||||
|
||||
+97
-87
@@ -46,6 +46,8 @@
|
||||
extern BOOLEAN gfHiddenInterrupt;
|
||||
extern BOOLEAN gfUseAlternateQueenPosition;
|
||||
extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance );
|
||||
void LogDecideInfo(SOLDIERTYPE *pSoldier);
|
||||
void LogKnowledgeInfo(SOLDIERTYPE *pSoldier);
|
||||
|
||||
// global status time counters to determine what takes the most time
|
||||
|
||||
@@ -68,6 +70,13 @@ INT8 ArmedVehicleDecideActionYellow(SOLDIERTYPE *pSoldier);
|
||||
INT8 ArmedVehicleDecideActionRed(SOLDIERTYPE *pSoldier);
|
||||
INT8 ArmedVehicleDecideActionBlack(SOLDIERTYPE *pSoldier);
|
||||
|
||||
STR8 gStr8AlertStatus[] = { "Green", "Yellow", "Red", "Black" };
|
||||
STR8 gStr8Attitude[] = { "DEFENSIVE", "BRAVESOLO", "BRAVEAID", "CUNNINGSOLO", "CUNNINGAID", "AGGRESSIVE", "MAXATTITUDES", "ATTACKSLAYONLY" };
|
||||
STR8 gStr8Orders[] = { "STATIONARY", "ONGUARD", "CLOSEPATROL", "FARPATROL", "POINTPATROL", "ONCALL", "SEEKENEMY", "RNDPTPATROL", "SNIPER" };
|
||||
STR8 gStr8Team[] = { "OUR_TEAM", "ENEMY_TEAM", "CREATURE_TEAM", "MILITIA_TEAM", "CIV_TEAM", "LAST_TEAM", "PLAYER_PLAN", "LAN_TEAM_ONE", "LAN_TEAM_TWO", "LAN_TEAM_THREE", "LAN_TEAM_FOUR" };
|
||||
STR8 gStr8Class[] = { "SOLDIER_CLASS_NONE", "SOLDIER_CLASS_ADMINISTRATOR", "SOLDIER_CLASS_ELITE", "SOLDIER_CLASS_ARMY", "SOLDIER_CLASS_GREEN_MILITIA", "SOLDIER_CLASS_REG_MILITIA", "SOLDIER_CLASS_ELITE_MILITIA", "SOLDIER_CLASS_CREATURE", "SOLDIER_CLASS_MINER", "SOLDIER_CLASS_ZOMBIE", "SOLDIER_CLASS_TANK", "SOLDIER_CLASS_JEEP", "SOLDIER_CLASS_BANDIT" };
|
||||
STR8 gStr8Knowledge[] = { "HEARD_3_TURNS_AGO", "HEARD_2_TURNS_AGO", "HEARD_LAST_TURN", "HEARD_THIS_TURN", "NOT_HEARD_OR_SEEN", "SEEN_CURRENTLY", "SEEN_THIS_TURN", "SEEN_LAST_TURN", "SEEN_2_TURNS_AGO", "SEEN_3_TURNS_AGO" };
|
||||
|
||||
void DoneScheduleAction( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
pSoldier->aiData.fAIFlags &= (~AI_CHECK_SCHEDULE);
|
||||
@@ -695,10 +704,6 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
|
||||
// Flugente: to prevent an accidental call
|
||||
if ( pSoldier->IsZombie() )
|
||||
return( ZombieDecideActionGreen(pSoldier) );
|
||||
|
||||
if ( ARMED_VEHICLE( pSoldier ) )
|
||||
return ArmedVehicleDecideActionGreen( pSoldier );
|
||||
|
||||
@@ -1547,10 +1552,6 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
|
||||
// Flugente: to prevent an accidental call
|
||||
if ( pSoldier->IsZombie() )
|
||||
return( ZombieDecideActionYellow(pSoldier) );
|
||||
|
||||
if (fCivilian || (gGameExternalOptions.fAllNamedNpcsDecideAction && pSoldier->ubProfile != NO_PROFILE))
|
||||
{
|
||||
if (pSoldier->flags.uiStatusFlags & SOLDIER_COWERING)
|
||||
@@ -2467,10 +2468,6 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
(pSoldier->aiData.bNeutral && gTacticalStatus.fCivGroupHostile[pSoldier->ubCivilianGroup] == CIV_GROUP_NEUTRAL) ||
|
||||
(pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
|
||||
|
||||
// Flugente: to prevent an accidental call
|
||||
if ( pSoldier->IsZombie() )
|
||||
return ZombieDecideActionRed(pSoldier);
|
||||
|
||||
// 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
|
||||
//INT16 ubOverallTacticalSituation = AssessTacticalSituation(pSoldier->bSide);
|
||||
@@ -2484,7 +2481,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
fProneSightCover = ProneSightCoverAtSpot(pSoldier, pSoldier->sGridNo);
|
||||
fProneSightCover = ProneSightCoverAtSpot(pSoldier, pSoldier->sGridNo, FALSE);
|
||||
if( !fProneSightCover || pSoldier->aiData.bUnderFire )
|
||||
{
|
||||
fDangerousSpot = TRUE;
|
||||
@@ -4534,10 +4531,6 @@ INT16 ubMinAPCost;
|
||||
#endif
|
||||
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack: soldier = %d, orders = %d, attitude = %d",pSoldier->ubID,pSoldier->aiData.bOrders,pSoldier->aiData.bAttitude));
|
||||
|
||||
// Flugente: to prevent an accidental call
|
||||
if ( pSoldier->IsZombie() )
|
||||
return( ZombieDecideActionBlack(pSoldier) );
|
||||
|
||||
ATTACKTYPE BestShot, BestThrow, BestStab ,BestAttack;//dnl ch69 150913
|
||||
BOOLEAN fCivilian = (PTR_CIVILIAN && (pSoldier->ubCivilianGroup == NON_CIV_GROUP || pSoldier->aiData.bNeutral || (pSoldier->ubBodyType >= FATCIV && pSoldier->ubBodyType <= CRIPPLECIV) ) );
|
||||
UINT8 ubBestStance = 1;
|
||||
@@ -6697,51 +6690,6 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
if (pSoldier->bOppCnt > 0)
|
||||
{
|
||||
pSoldier->aiData.bAlertStatus = STATUS_BLACK; // opponent(s) in sight
|
||||
}
|
||||
else
|
||||
{
|
||||
pSoldier->aiData.bAlertStatus = STATUS_RED; // enemy sector
|
||||
|
||||
/*
|
||||
// wow, JA1 stuff...
|
||||
// good guys all have a built-in, magic, "enemy detecting radar"...
|
||||
if (Status.enemies)
|
||||
pSoldier->aiData.bAlertStatus = STATUS_RED; // enemy sector
|
||||
else
|
||||
{
|
||||
pSoldier->aiData.bAlertStatus = STATUS_GREEN; // secured sector
|
||||
|
||||
// if he just dropped back from alert status, and it's a GUARD
|
||||
if ((oldStatus >= STATUS_RED) && (pSoldier->manCategory == MAN_GUARD))
|
||||
{
|
||||
if (TileIsOutOfBounds(pSoldier->whereIWas)) // not assigned to any trees
|
||||
// FUTURE ENHANCEMENT: Look for unguarded trees with tappers
|
||||
pSoldier->orders = ONCALL;
|
||||
else // assigned to trees
|
||||
// FUTURE ENHANCEMENT: If his tree is now tapperless, go ONCALL
|
||||
pSoldier->orders = CLOSEPATROL; // go back to his tree area
|
||||
|
||||
// turn off any existing bypass to Green and its "hyper-activity"
|
||||
pSoldier->bypassToGreen = FALSE;
|
||||
|
||||
// turn off the "inTheWay" flag, may have been set during TurnBased
|
||||
pSoldier->inTheWay = FALSE;
|
||||
|
||||
// make the guard put his gun away if he has it drawn
|
||||
HandleNoMoreTarget(pSoldier);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( gTacticalStatus.bBoxingState == NOT_BOXING )
|
||||
{
|
||||
|
||||
@@ -6806,7 +6754,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
|
||||
|
||||
// ------------------------------ ZOMBIE AI --------------------------
|
||||
INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
/*INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
DOUBLE iChance, iSneaky = 10;
|
||||
INT8 bInWater;
|
||||
@@ -7206,9 +7154,9 @@ INT8 ZombieDecideActionGreen(SOLDIERTYPE *pSoldier)
|
||||
// for realtime, regular AI guys will use a standard wait set outside of here
|
||||
pSoldier->aiData.usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
}*/
|
||||
|
||||
INT8 ZombieDecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
/*INT8 ZombieDecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
UINT8 ubNoiseDir;
|
||||
INT32 sNoiseGridNo;
|
||||
@@ -7440,10 +7388,10 @@ INT8 ZombieDecideActionYellow(SOLDIERTYPE *pSoldier)
|
||||
// by default, if everything else fails, just stands in place without turning
|
||||
pSoldier->aiData.usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
/*INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
INT32 iDummy;
|
||||
INT32 iChance,sClosestOpponent,sClosestFriend;
|
||||
@@ -8072,14 +8020,6 @@ INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
// 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, &fClimb))) )
|
||||
{
|
||||
// addition: if soldier is bleeding then reduce bleeding and do nothing
|
||||
/*if ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD )
|
||||
{
|
||||
// no! zombies don't bandage themselves!
|
||||
// reduce bleeding by 1 point per AP (in RT, APs will get recalculated so it's okay)
|
||||
// pSoldier->bBleeding = __max( 0, pSoldier->bBleeding - (pSoldier->bActionPoints/2) );
|
||||
return( AI_ACTION_NONE ); // will end-turn/wait depending on whether we're in TB or realtime
|
||||
}*/
|
||||
#ifdef RECORDNET
|
||||
fprintf(NetDebugFile,"\tZombieDecideActionRed: guynum %d switching to GREEN AI...\n",pSoldier->ubID);
|
||||
#endif
|
||||
@@ -8126,9 +8066,9 @@ INT8 ZombieDecideActionRed(SOLDIERTYPE *pSoldier)
|
||||
|
||||
pSoldier->aiData.usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
}*/
|
||||
|
||||
INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier)
|
||||
/*INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
INT32 iCoverPercentBetter = 0;
|
||||
INT32 iOffense, iDefense, iChance;
|
||||
@@ -8685,12 +8625,12 @@ INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier)
|
||||
}
|
||||
|
||||
// get the location of the closest reachable opponent
|
||||
/* Flugente 22.02.2012 - A few clarifications: I changed ClosestSeenOpponent so that for zombies, this function also returns an opponent if he is on the
|
||||
* roof of a building, we are not, but our GridNo belongs to that same building.
|
||||
* If that is the case, it is clear that we have to get on that roof. However, we cannot do that in BlackState. If, by pure chance, we can still see our
|
||||
* enemy, we cannot climb (there is no climbing option in BlackState sofar).
|
||||
* So, I changed the code so that now we will climb the roof.
|
||||
*/
|
||||
// Flugente 22.02.2012 - A few clarifications: I changed ClosestSeenOpponent so that for zombies, this function also returns an opponent if he is on the
|
||||
// roof of a building, we are not, but our GridNo belongs to that same building.
|
||||
// If that is the case, it is clear that we have to get on that roof. However, we cannot do that in BlackState. If, by pure chance, we can still see our
|
||||
// enemy, we cannot climb (there is no climbing option in BlackState sofar).
|
||||
// So, I changed the code so that now we will climb the roof.
|
||||
|
||||
INT32 targetGridNo = -1;
|
||||
INT8 targetbLevel = 0;
|
||||
sClosestOpponent = ClosestSeenOpponentWithRoof(pSoldier, &targetGridNo, &targetbLevel);
|
||||
@@ -8838,9 +8778,9 @@ INT8 ZombieDecideActionBlack(SOLDIERTYPE *pSoldier)
|
||||
pSoldier->aiData.usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
INT8 ZombieDecideAction( SOLDIERTYPE *pSoldier )
|
||||
/*INT8 ZombieDecideAction( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
INT8 bAction = AI_ACTION_NONE;
|
||||
|
||||
@@ -8882,7 +8822,7 @@ INT8 ZombieDecideAction( SOLDIERTYPE *pSoldier )
|
||||
#endif
|
||||
|
||||
return(bAction);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
INT8 ArmedVehicleDecideAction( SOLDIERTYPE *pSoldier )
|
||||
@@ -9845,7 +9785,7 @@ INT8 ArmedVehicleDecideActionRed( SOLDIERTYPE *pSoldier)
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
fProneSightCover = ProneSightCoverAtSpot( pSoldier, pSoldier->sGridNo );
|
||||
fProneSightCover = ProneSightCoverAtSpot(pSoldier, pSoldier->sGridNo, FALSE);
|
||||
if ( !fProneSightCover || pSoldier->aiData.bUnderFire )
|
||||
{
|
||||
fDangerousSpot = TRUE;
|
||||
@@ -11901,3 +11841,73 @@ INT8 ArmedVehicleDecideActionBlack( SOLDIERTYPE *pSoldier )
|
||||
pSoldier->aiData.usActionData = NOWHERE;
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
|
||||
extern UINT32 guiTurnCnt;
|
||||
extern UINT32 guiReinforceTurn;
|
||||
extern UINT32 guiArrived;
|
||||
|
||||
void LogDecideInfo(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Turn num %d aware %d", guiTurnCnt, gTacticalStatus.Team[pSoldier->bTeam].bAwareOfOpposition));
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("current team %d interrupt occurred %d", gTacticalStatus.ubCurrentTeam, gTacticalStatus.fInterruptOccurred));
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("AP=%d/%d %s %s %s %s %s", pSoldier->bActionPoints, pSoldier->bInitialActionPoints, gStr8AlertStatus[pSoldier->aiData.bAlertStatus], gStr8Orders[pSoldier->aiData.bOrders], gStr8Attitude[pSoldier->aiData.bAttitude], gStr8Team[pSoldier->bTeam], gStr8Class[pSoldier->ubSoldierClass]));
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Health %d/%d Breath %d/%d Shock %d Tolerance %d AI Morale %d Morale %d", pSoldier->stats.bLife, pSoldier->stats.bLifeMax, pSoldier->bBreath, pSoldier->bBreathMax, pSoldier->aiData.bShock, CalcSuppressionTolerance(pSoldier), pSoldier->aiData.bAIMorale, pSoldier->aiData.bMorale));
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Spot %d level %d opponents %d", pSoldier->sGridNo, pSoldier->pathing.bLevel, pSoldier->aiData.bOppCnt));
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("ubServiceCount %d ubServicePartner %d fDoingSurgery %d", pSoldier->ubServiceCount, pSoldier->ubServicePartner, pSoldier->fDoingSurgery));
|
||||
if (pSoldier->usAnimState == COWERING || pSoldier->usAnimState == COWERING_PRONE)
|
||||
{
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Cowering"));
|
||||
}
|
||||
if (pSoldier->usAnimState == GIVING_AID || pSoldier->usAnimState == GIVING_AID_PRN)
|
||||
{
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Giving aid"));
|
||||
}
|
||||
//CHAR8 str8[1024];
|
||||
|
||||
// show watched locations
|
||||
INT8 bLoop;
|
||||
for (bLoop = 0; bLoop < NUM_WATCHED_LOCS; bLoop++)
|
||||
{
|
||||
if (!TileIsOutOfBounds(gsWatchedLoc[pSoldier->ubID][bLoop]))
|
||||
{
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Watched location %d level %d points %d", gsWatchedLoc[pSoldier->ubID][bLoop], gbWatchedLocLevel[pSoldier->ubID][bLoop], gubWatchedLocPoints[pSoldier->ubID][bLoop]));
|
||||
}
|
||||
}
|
||||
|
||||
LogKnowledgeInfo(pSoldier);
|
||||
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("What I know %d", WhatIKnowThatPublicDont(pSoldier, FALSE)));
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("Has Gun %d, Short range weapon %d, Gun Range %d, Gun Ammo %d, Gun Scoped %d ", AICheckHasGun(pSoldier), AICheckShortWeaponRange(pSoldier), AIGunRange(pSoldier), AIGunAmmo(pSoldier), AIGunScoped(pSoldier)));
|
||||
}
|
||||
|
||||
void LogKnowledgeInfo(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
//CHAR8 str8[1024];
|
||||
//memset(str8, 0, 1024 * sizeof(char));
|
||||
|
||||
// show public opponents
|
||||
for (UINT16 oppID = 0; oppID < MAX_NUM_SOLDIERS; oppID++)
|
||||
{
|
||||
if (gbPublicOpplist[pSoldier->bTeam][oppID] != NOT_HEARD_OR_SEEN &&
|
||||
!MercPtrs[oppID]->aiData.bNeutral)
|
||||
{
|
||||
//wcstombs(str8, MercPtrs[oppID]->GetName(), wcslen(MercPtrs[oppID]->GetName())+1);
|
||||
//wcstombs(str8, MercPtrs[oppID]->GetName(), 1024 - 1);
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("public opponent [%d] knowledge %s gridno %d level %d", oppID, gStr8Knowledge[gbPublicOpplist[pSoldier->bTeam][oppID] - OLDEST_HEARD_VALUE], gsPublicLastKnownOppLoc[pSoldier->bTeam][oppID], gbPublicLastKnownOppLevel[pSoldier->bTeam][oppID]));
|
||||
//swprintf( pStrInfo, L"%s[%d] %s %s\n", pStrInfo, oppID, MercPtrs[oppID]->GetName(), SeenStr(gbPublicOpplist[pSoldier->bTeam][oppID]) );
|
||||
}
|
||||
}
|
||||
// show personal opponents
|
||||
for (UINT16 oppID = 0; oppID < MAX_NUM_SOLDIERS; oppID++)
|
||||
{
|
||||
if (pSoldier->aiData.bOppList[oppID] != NOT_HEARD_OR_SEEN &&
|
||||
!MercPtrs[oppID]->aiData.bNeutral)
|
||||
{
|
||||
//wcstombs(str8, MercPtrs[oppID]->GetName(), wcslen(MercPtrs[oppID]->GetName())+1);
|
||||
//wcstombs(str8, MercPtrs[oppID]->GetName(), 1024 - 1);
|
||||
DebugAI(AI_MSG_INFO, pSoldier, String("personal opponent [%d] knowledge %s gridno %d level %d", oppID, gStr8Knowledge[pSoldier->aiData.bOppList[oppID] - OLDEST_HEARD_VALUE], gsLastKnownOppLoc[pSoldier->ubID][oppID], gbLastKnownOppLevel[pSoldier->ubID][oppID]));
|
||||
//swprintf( pStrInfo, L"%s[%d] %s %s\n", pStrInfo, oppID, MercPtrs[oppID]->GetName(), SeenStr(pSoldier->aiData.bOppList[oppID]) );
|
||||
}
|
||||
}
|
||||
}
|
||||
+582
-65
@@ -290,14 +290,13 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
INT16 sTempX, sTempY;
|
||||
FLOAT dMyX, dMyY, dHisX, dHisY;
|
||||
INT8 bHisBestCTGT, bHisActualCTGT, bHisCTGT, bMyCTGT;
|
||||
INT32 iRangeChange, iRangeFactor, iRangeFactorMultiplier;
|
||||
INT32 iRangeChange, iRangeFactor, iRCD;
|
||||
SOLDIERTYPE *pHim;
|
||||
|
||||
// sevenfm
|
||||
INT8 bHisLevel;
|
||||
INT8 bMyLevel;
|
||||
INT32 sDist;
|
||||
UINT8 ubCoverReduction;
|
||||
|
||||
dMyX = dMyY = dHisX = dHisY = -1.0;
|
||||
|
||||
@@ -338,7 +337,8 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
}
|
||||
|
||||
|
||||
if (InWaterOrGas(pHim,sHisGridNo))
|
||||
if (DeepWater(sHisGridNo, bHisLevel) || InGas(pHim, sHisGridNo))
|
||||
//if (InWaterOrGas(pHim,sHisGridNo))
|
||||
{
|
||||
bHisActualCTGT = 0;
|
||||
}
|
||||
@@ -378,7 +378,8 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
|
||||
// if my intended gridno is in water or gas, I can't attack at all from there
|
||||
// here, for smoke, consider bad
|
||||
if (InWaterGasOrSmoke(pMe,sMyGridNo))
|
||||
if (DeepWater(sMyGridNo, bMyLevel) || InGas(pMe, sMyGridNo))
|
||||
//if (InWaterGasOrSmoke(pMe,sMyGridNo))
|
||||
{
|
||||
bMyCTGT = 0;
|
||||
}
|
||||
@@ -392,8 +393,6 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
pHim->dXPos = (FLOAT) sTempX;
|
||||
pHim->dYPos = (FLOAT) sTempY;
|
||||
}
|
||||
// bMyCTGT = ChanceToGetThrough(pMe,sHisGridNo,FAKE,ACTUAL,TESTWALLS,9999,M9PISTOL,NOT_FOR_LOS); // assume a gunshot
|
||||
// bMyCTGT = SoldierToLocationChanceToGetThrough( pMe, sHisGridNo, pMe->bTargetLevel, pMe->bTargetCubeLevel );
|
||||
|
||||
// let's not assume anything about the stance the enemy might take, so take an average
|
||||
// value... no cover give a higher value than partial cover
|
||||
@@ -423,6 +422,39 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
pHim->dYPos = dHisY; // and the 'y'
|
||||
}
|
||||
|
||||
sDist = PythSpacesAway(sMyGridNo, sHisGridNo);
|
||||
|
||||
if (gGameExternalOptions.fAIBetterCover)
|
||||
{
|
||||
// sevenfm: special calculations for zombies: zombie is very dangerous at close range
|
||||
if (pHim->IsZombie() || !AICheckHasGun(pHim))
|
||||
{
|
||||
if (sDist < (INT32)(DAY_VISION_RANGE / 2))
|
||||
{
|
||||
// 100 - 25
|
||||
bHisCTGT = 100 - 150 * sDist / DAY_VISION_RANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 25 - 0
|
||||
bHisCTGT = 100 * DAY_VISION_RANGE * DAY_VISION_RANGE / (16 * sDist * sDist);
|
||||
}
|
||||
}
|
||||
|
||||
// sevenfm: if soldier has no gun, use different calculation
|
||||
if (pMe->IsZombie() || !AICheckHasGun(pMe))
|
||||
{
|
||||
if (sDist < (INT32)(DAY_VISION_RANGE / 2))
|
||||
{
|
||||
bMyCTGT = 100 - 150 * sDist / DAY_VISION_RANGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bMyCTGT = 100 * DAY_VISION_RANGE * DAY_VISION_RANGE / (16 * sDist * sDist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// these value should be < 1 million each
|
||||
iHisPosValue = bHisCTGT * Threat[uiThreatIndex].iValue * Threat[uiThreatIndex].iAPs;
|
||||
iMyPosValue = bMyCTGT * iMyThreat * iMyAPsLeft;
|
||||
@@ -431,18 +463,20 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
// max 25% at DAY_VISION_RANGE/2, 0 at zero range
|
||||
if( gGameExternalOptions.fAIBetterCover )
|
||||
{
|
||||
if( AnyCoverFromSpot(sMyGridNo, bMyLevel, sHisGridNo, bHisLevel) )
|
||||
UINT8 ubCoverBonus = 25;
|
||||
if (sDist < (INT32)(DAY_VISION_RANGE / 2))
|
||||
{
|
||||
ubCoverReduction = 25;
|
||||
|
||||
sDist = PythSpacesAway(sMyGridNo, sHisGridNo);
|
||||
|
||||
if (sDist < (INT32)(DAY_VISION_RANGE / 2))
|
||||
{
|
||||
ubCoverReduction = ubCoverReduction * 2 * sDist / DAY_VISION_RANGE;
|
||||
}
|
||||
iHisPosValue -= iHisPosValue * ubCoverReduction / 100;
|
||||
iMyPosValue += iMyPosValue * ubCoverReduction / 100;
|
||||
ubCoverBonus = ubCoverBonus * 2 * sDist / DAY_VISION_RANGE;
|
||||
}
|
||||
if (!pHim->IsZombie() && AICheckHasGun(pHim) && AnyCoverFromSpot(sMyGridNo, bMyLevel, sHisGridNo, bHisLevel))
|
||||
{
|
||||
iHisPosValue -= iHisPosValue * ubCoverBonus / 100;
|
||||
iMyPosValue += iMyPosValue * ubCoverBonus / 100;
|
||||
}
|
||||
if (!pMe->IsZombie() && AICheckHasGun(pMe) && AnyCoverFromSpot(sHisGridNo, bHisLevel, sMyGridNo, bMyLevel))
|
||||
{
|
||||
iHisPosValue += iHisPosValue * ubCoverBonus / 100;
|
||||
iMyPosValue -= iMyPosValue * ubCoverBonus / 100;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,66 +493,62 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
}
|
||||
|
||||
|
||||
// if my positional value is worth something at all here
|
||||
if (iMyPosValue > 0)
|
||||
// if my positional value is worth something at all here
|
||||
if (iMyPosValue > 0)
|
||||
{
|
||||
// if I CAN'T crouch when I get there, that makes it significantly less
|
||||
// appealing a spot (how much depends on range), so that's a penalty to me
|
||||
if (iMyAPsLeft < GetAPsCrouch(pMe,TRUE))
|
||||
// subtract another 1 % penalty for NOT being able to crouch per tile
|
||||
// the farther away we are, the bigger a difference crouching will make!
|
||||
iMyPosValue -= ((iMyPosValue * (AIM_PENALTY_TARGET_CROUCHED + (iRange / CELL_X_SIZE))) / 100);
|
||||
// if I CAN'T crouch when I get there, that makes it significantly less
|
||||
// appealing a spot (how much depends on range), so that's a penalty to me
|
||||
if (iMyAPsLeft < GetAPsCrouch(pMe, TRUE))
|
||||
// subtract another 1 % penalty for NOT being able to crouch per tile
|
||||
// the farther away we are, the bigger a difference crouching will make!
|
||||
iMyPosValue -= ((iMyPosValue * (AIM_PENALTY_TARGET_CROUCHED + (iRange / CELL_X_SIZE))) / 100);
|
||||
}
|
||||
|
||||
|
||||
// high morale prefers decreasing the range (positive factor), while very
|
||||
// low morale (HOPELESS) prefers increasing it
|
||||
|
||||
// if (bHisCTGT < 100 || (morale - 1 < 0))
|
||||
iRCD = RangeChangeDesire(pMe);
|
||||
|
||||
if (iRCD)
|
||||
{
|
||||
iRangeChange = Threat[uiThreatIndex].iOrigRange - iRange;
|
||||
|
||||
iRangeFactorMultiplier = RangeChangeDesire( pMe );
|
||||
|
||||
if (iRangeFactorMultiplier)
|
||||
if (iRangeChange)
|
||||
{
|
||||
iRangeChange = Threat[uiThreatIndex].iOrigRange - iRange;
|
||||
//iRangeFactor = (iRangeChange * (morale - 1)) / 4;
|
||||
iRangeFactor = (iRangeChange * iRCD) / 2;
|
||||
|
||||
if (iRangeChange)
|
||||
// sevenfm: reduce range bonus depending on cover
|
||||
if (gGameExternalOptions.fAIBetterCover)
|
||||
{
|
||||
//iRangeFactor = (iRangeChange * (morale - 1)) / 4;
|
||||
iRangeFactor = (iRangeChange * iRangeFactorMultiplier) / 2;
|
||||
|
||||
// sevenfm: reduce range bonus depending on cover
|
||||
if( gGameExternalOptions.fAIBetterCover )
|
||||
if (!AnyCoverFromSpot(sMyGridNo, bMyLevel, sHisGridNo, bHisLevel) &&
|
||||
CountSeenEnemiesLastTurn(pMe) > CountNearbyFriends(pMe, sMyGridNo, DAY_VISION_RANGE / 2))
|
||||
{
|
||||
if( !AnyCoverFromSpot(sMyGridNo, bMyLevel, sHisGridNo, bHisLevel) &&
|
||||
CountSeenEnemiesLastTurn(pMe) > CountNearbyFriends(pMe, sMyGridNo, DAY_VISION_RANGE / 2) )
|
||||
{
|
||||
iRangeFactor = iRangeFactor * (100 - bHisCTGT * __min(Threat[uiThreatIndex].iAPs, APBPConstants[AP_MAXIMUM]) / APBPConstants[AP_MAXIMUM]) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGCOVER
|
||||
DebugAI( String( "CalcCoverValue: iRangeChange %d, iRangeFactor %d\n", iRangeChange, iRangeFactor ) );
|
||||
#endif
|
||||
|
||||
// aggression booster for stupider enemies
|
||||
iMyPosValue += 100 * iRangeFactor * ( 5 - SoldierDifficultyLevel( pMe ) ) / 5 ;
|
||||
|
||||
// if factor is positive increase positional value, else decrease it
|
||||
// change both values, since one or the other could be 0
|
||||
if (iRangeFactor > 0)
|
||||
{
|
||||
|
||||
iMyPosValue = (iMyPosValue * (100 + iRangeFactor)) / 100;
|
||||
iHisPosValue = (100 * iHisPosValue) / (100 + iRangeFactor);
|
||||
}
|
||||
else if (iRangeFactor < 0)
|
||||
{
|
||||
iMyPosValue = (100 * iMyPosValue) / (100 - iRangeFactor);
|
||||
iHisPosValue = (iHisPosValue * (100 - iRangeFactor)) / 100;
|
||||
iRangeFactor = iRangeFactor * (100 - bHisCTGT * __min(Threat[uiThreatIndex].iAPs, APBPConstants[AP_MAXIMUM]) / APBPConstants[AP_MAXIMUM]) / 100;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGCOVER
|
||||
DebugAI( String( "CalcCoverValue: iRangeChange %d, iRangeFactor %d\n", iRangeChange, iRangeFactor ) );
|
||||
#endif
|
||||
|
||||
// aggression booster for stupider enemies
|
||||
iMyPosValue += 100 * iRangeFactor * (5 - SoldierDifficultyLevel(pMe)) / 5;
|
||||
|
||||
// if factor is positive increase positional value, else decrease it
|
||||
// change both values, since one or the other could be 0
|
||||
if (iRangeFactor > 0)
|
||||
{
|
||||
|
||||
iMyPosValue = (iMyPosValue * (100 + iRangeFactor)) / 100;
|
||||
iHisPosValue = (100 * iHisPosValue) / (100 + iRangeFactor);
|
||||
}
|
||||
else if (iRangeFactor < 0)
|
||||
{
|
||||
iMyPosValue = (100 * iMyPosValue) / (100 - iRangeFactor);
|
||||
iHisPosValue = (iHisPosValue * (100 - iRangeFactor)) / 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,7 +557,7 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
iReductionFactor = ((MAX_THREAT_RANGE - iRange) * Threat[uiThreatIndex].iCertainty) /
|
||||
MAX_THREAT_RANGE;
|
||||
|
||||
// divide by a 100 to make the numbers more managable and avoid 32-bit limit
|
||||
// divide by a 100 to make the numbers more manageable and avoid 32-bit limit
|
||||
iThisScale = max( iMyPosValue, iHisPosValue) / 100;
|
||||
iThisScale = (iThisScale * iReductionFactor) / 100;
|
||||
*iTotalScale += iThisScale;
|
||||
@@ -535,7 +565,7 @@ INT32 CalcCoverValue(SOLDIERTYPE *pMe, INT32 sMyGridNo, INT32 iMyThreat, INT32 i
|
||||
|
||||
// POSITIVE COVER VALUE INDICATES THE COVER BENEFITS ME, NEGATIVE RESULT
|
||||
// MEANS IT BENEFITS THE OTHER GUY.
|
||||
// divide by a 100 to make the numbers more managable and avoid 32-bit limit
|
||||
// divide by a 100 to make the numbers more manageable and avoid 32-bit limit
|
||||
iCoverValue = (iMyPosValue - iHisPosValue) / 100;
|
||||
iCoverValue = (iCoverValue * iReductionFactor) / 100;
|
||||
|
||||
@@ -604,7 +634,7 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
UINT8 ubBackgroundLightLevel;
|
||||
UINT8 ubBackgroundLightPercent = 0;
|
||||
UINT8 ubLightPercentDifference;
|
||||
BOOLEAN fNight;
|
||||
BOOLEAN fNight;
|
||||
|
||||
// sevenfm
|
||||
UINT8 ubNearbyFriends;
|
||||
@@ -1057,6 +1087,13 @@ INT32 FindBestNearbyCover(SOLDIERTYPE *pSoldier, INT32 morale, INT32 *piPercentB
|
||||
continue;
|
||||
}
|
||||
|
||||
// zombies only want to hide
|
||||
if (pSoldier->IsZombie() && !SightCoverAtSpot(pSoldier, sGridNo, TRUE))
|
||||
{
|
||||
//DebugCover(pSoldier, String("zombie: no sight cover at new spot, 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
|
||||
@@ -3145,3 +3182,483 @@ INT32 FindNearestPassableSpot( INT32 sGridNo, UINT8 usSearchRadius )
|
||||
|
||||
return( sNearestSpot );
|
||||
}
|
||||
|
||||
INT32 FindAdvanceSpot(SOLDIERTYPE *pSoldier, INT32 sTargetSpot, INT8 bAction, UINT8 ubType, BOOLEAN fUnlimited)
|
||||
{
|
||||
INT32 sGridNo, sRealGridNo;
|
||||
INT32 sBestSpot = NOWHERE;
|
||||
INT32 iSearchRange = min(AI_PATHCOST_RADIUS, MAX_TILES_MOVE_TURN);
|
||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||
INT32 iPathCost, iBestPathCost = 0;
|
||||
INT16 usMovementMode;
|
||||
INT32 iRoamRange, iDistFromOrigin, sOrigin;
|
||||
//BOOLEAN fClimbingNecessary;
|
||||
//INT32 sClimbGridNo;
|
||||
BOOLEAN fHasMortar;
|
||||
|
||||
if (!pSoldier)
|
||||
{
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
// check target location
|
||||
if (!NewOKDestination(pSoldier, sTargetSpot, FALSE, pSoldier->pathing.bLevel))
|
||||
{
|
||||
//ScreenMsg(FONT_ORANGE, MSG_INTERFACE, L"bad destination %d", sTargetSpot);
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
fHasMortar = AICheckIsMortarOperator(pSoldier);
|
||||
|
||||
usMovementMode = DetermineMovementMode(pSoldier, bAction);
|
||||
|
||||
UINT8 ubReserveAP = 0;
|
||||
|
||||
if (ubType != ADVANCE_SPOT_SIGHT_COVER)
|
||||
{
|
||||
if (usMovementMode == RUNNING || usMovementMode == WALKING)
|
||||
{
|
||||
ubReserveAP = APBPConstants[AP_CHANGE_FACING] + GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ubReserveAP = APBPConstants[AP_LOOK_CROUCHED] + GetAPsProne(pSoldier, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
if (pSoldier->bActionPoints <= ubReserveAP)
|
||||
{
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
// check that location is reachable
|
||||
iBestPathCost = EstimatePlotPath(pSoldier, sTargetSpot, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, FALSE, 0);
|
||||
if (iBestPathCost == 0)
|
||||
{
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
iRoamRange = RoamingRange(pSoldier, &sOrigin);
|
||||
|
||||
// set AP limit
|
||||
gubNPCAPBudget = pSoldier->bActionPoints - ubReserveAP;
|
||||
// set the distance limit of the square region
|
||||
gubNPCDistLimit = (UINT8)iSearchRange;
|
||||
|
||||
// determine maximum horizontal limits
|
||||
sMaxLeft = min(iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
||||
//NumMessage("sMaxLeft = ",sMaxLeft);
|
||||
sMaxRight = min(iSearchRange, MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||
//NumMessage("sMaxRight = ",sMaxRight);
|
||||
|
||||
// determine maximum vertical limits
|
||||
sMaxUp = min(iSearchRange, (pSoldier->sGridNo / MAXROW));
|
||||
//NumMessage("sMaxUp = ",sMaxUp);
|
||||
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...
|
||||
|
||||
// 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))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
gpWorldLevelData[sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||
}
|
||||
}
|
||||
|
||||
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0);
|
||||
|
||||
// Turn off the "reachable" flag for his current location
|
||||
// so we don't consider it
|
||||
gpWorldLevelData[pSoldier->sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||
|
||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||
{
|
||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||
{
|
||||
// calculate the next potential gridno
|
||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
|
||||
if (!(sGridNo >= 0 && sGridNo < WORLD_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(gpWorldLevelData[sGridNo].uiFlags & MAPELEMENT_REACHABLE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sGridNo == pSoldier->pathing.sBlackList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check roaming range
|
||||
if (iRoamRange < MAX_ROAMING_RANGE && !TileIsOutOfBounds(sOrigin))
|
||||
{
|
||||
iDistFromOrigin = SpacesAway(sOrigin, sGridNo);
|
||||
if (iDistFromOrigin > iRoamRange)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// check if we will be closer to target spot
|
||||
if (PythSpacesAway(sGridNo, sTargetSpot) > PythSpacesAway(pSoldier->sGridNo, sTargetSpot))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// exclude locations with tear/mustard gas (at this point, smoke is cool!)
|
||||
if (InGas(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip lighted spots
|
||||
if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) &&
|
||||
!InLightAtNight(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||
continue;
|
||||
|
||||
// skip deep water
|
||||
if (DeepWater(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip water
|
||||
if (Water(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip locations too close to target spot
|
||||
if (PythSpacesAway(sGridNo, sTargetSpot) < (INT16)(DAY_VISION_RANGE / 4))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid smoke
|
||||
if (InSmoke(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip if this spot has no cover nearby
|
||||
if ((ubType == ADVANCE_SPOT_ANY_COVER || fUnlimited) &&
|
||||
!FindObstacleNearSpot(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid locations near fresh corpses
|
||||
if (!pSoldier->IsZombie() && GetNearestRottingCorpseAIWarning(sGridNo) > 0)
|
||||
//if (CorpseWarning(pSoldier, sGridNo, pSoldier->pathing.bLevel, TRUE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid overcrowding
|
||||
if (!pSoldier->IsZombie() && NumberOfTeamMatesAdjacent(pSoldier, sGridNo) > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!LegalNPCDestination(pSoldier, sGridNo, IGNORE_PATH, NOWATER, 0))
|
||||
{
|
||||
continue; // skip on to the next potential grid
|
||||
}
|
||||
|
||||
// sevenfm: avoid rooms for mortar operators
|
||||
if (!AICheckUnderground() &&
|
||||
pSoldier->pathing.bLevel == 0 &&
|
||||
fHasMortar &&
|
||||
InARoom(sGridNo, NULL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ubType == ADVANCE_SPOT_SIGHT_COVER)
|
||||
{
|
||||
// skip locations with no sight cover
|
||||
if (!SightCoverAtSpot(pSoldier, sGridNo, fUnlimited))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (ubType == ADVANCE_SPOT_PRONE_COVER)
|
||||
{
|
||||
// check prone sight cover at spot
|
||||
if (!ProneSightCoverAtSpot(pSoldier, sGridNo, fUnlimited))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// check that we'll have enough APs to go prone at target spot
|
||||
/*iPathCost = EstimatePlotPath( pSoldier, sGridNo, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, FALSE, 0);
|
||||
if( pSoldier->bActionPoints - iPathCost < GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE) + APBPConstants[AP_CHANGE_FACING] )
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
}
|
||||
else if (ubType == ADVANCE_SPOT_ANY_COVER)
|
||||
{
|
||||
// check any cover at spot
|
||||
if (!AnyCoverAtSpot(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// check that we'll have enough APs to go prone at target spot
|
||||
/*iPathCost = EstimatePlotPath( pSoldier, sGridNo, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, FALSE, 0);
|
||||
if( pSoldier->bActionPoints - iPathCost < GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE) + APBPConstants[AP_CHANGE_FACING] )
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
}
|
||||
|
||||
sRealGridNo = pSoldier->sGridNo;
|
||||
pSoldier->sGridNo = sGridNo;
|
||||
iPathCost = EstimatePlotPath(pSoldier, sTargetSpot, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, FALSE, 0);
|
||||
//iPathCost = PlotPath(pSoldier, sTargetSpot, FALSE, FALSE, FALSE, usMovementMode, pSoldier->bStealthMode, FALSE, 0);
|
||||
//iPathCost = EstimatePathCostToLocation( pSoldier, sTargetSpot, pSoldier->pathing.bLevel, TRUE, &fClimbingNecessary, &sClimbGridNo );
|
||||
pSoldier->sGridNo = sRealGridNo;
|
||||
|
||||
// skip location if no path to target spot
|
||||
if (iPathCost == 0)
|
||||
{
|
||||
//ScreenMsg(FONT_ORANGE, MSG_INTERFACE, L"cannot find path to destination %d at %d", sTargetSpot, sGridNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
//if( sBestSpot == NOWHERE || iPathCost < iBestPathCost )
|
||||
if (iPathCost < iBestPathCost)
|
||||
{
|
||||
sBestSpot = sGridNo;
|
||||
iBestPathCost = iPathCost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gubNPCAPBudget = 0;
|
||||
gubNPCDistLimit = 0;
|
||||
|
||||
return(sBestSpot);
|
||||
}
|
||||
|
||||
// find spot with cover, max dist from opponents
|
||||
INT32 FindRetreatSpot(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
INT32 sGridNo;
|
||||
INT32 sBestSpot = NOWHERE;
|
||||
INT32 iSearchRange = MAX_TILES_MOVE_TURN;
|
||||
INT16 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset;
|
||||
INT16 usMovementMode;
|
||||
INT32 iRoamRange, iDistFromOrigin, sOrigin;
|
||||
//BOOLEAN fClimbingNecessary;
|
||||
//INT32 sClimbGridNo;
|
||||
UINT8 ubReserveAP;
|
||||
INT8 bAction = AI_ACTION_TAKE_COVER;
|
||||
INT32 sClosestOpponent;
|
||||
INT16 sDistance, sClosestDistance;
|
||||
|
||||
if (!pSoldier)
|
||||
{
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||
if (TileIsOutOfBounds(sClosestOpponent))
|
||||
{
|
||||
// no one to hide from
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
sClosestDistance = PythSpacesAway(pSoldier->sGridNo, sClosestOpponent);
|
||||
|
||||
//ubReserveAP = GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE) + APBPConstants[AP_CHANGE_FACING];
|
||||
ubReserveAP = GetAPsCrouch(pSoldier, TRUE) + APBPConstants[AP_CHANGE_FACING];
|
||||
|
||||
if (pSoldier->bActionPoints <= ubReserveAP)
|
||||
{
|
||||
return NOWHERE;
|
||||
}
|
||||
|
||||
iRoamRange = RoamingRange(pSoldier, &sOrigin);
|
||||
|
||||
// set AP limit
|
||||
gubNPCAPBudget = pSoldier->bActionPoints;
|
||||
// set the distance limit of the square region
|
||||
gubNPCDistLimit = (UINT8)iSearchRange;
|
||||
|
||||
// determine maximum horizontal limits
|
||||
sMaxLeft = min(iSearchRange, (pSoldier->sGridNo % MAXCOL));
|
||||
//NumMessage("sMaxLeft = ",sMaxLeft);
|
||||
sMaxRight = min(iSearchRange, MAXCOL - ((pSoldier->sGridNo % MAXCOL) + 1));
|
||||
//NumMessage("sMaxRight = ",sMaxRight);
|
||||
|
||||
// determine maximum vertical limits
|
||||
sMaxUp = min(iSearchRange, (pSoldier->sGridNo / MAXROW));
|
||||
//NumMessage("sMaxUp = ",sMaxUp);
|
||||
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...
|
||||
|
||||
// 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))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
gpWorldLevelData[sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||
}
|
||||
}
|
||||
|
||||
usMovementMode = DetermineMovementMode(pSoldier, bAction);
|
||||
FindBestPath(pSoldier, GRIDSIZE, pSoldier->pathing.bLevel, usMovementMode, COPYREACHABLE, 0);
|
||||
|
||||
// Turn off the "reachable" flag for his current location
|
||||
// so we don't consider it
|
||||
gpWorldLevelData[pSoldier->sGridNo].uiFlags &= ~(MAPELEMENT_REACHABLE);
|
||||
|
||||
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
||||
{
|
||||
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
||||
{
|
||||
// calculate the next potential gridno
|
||||
sGridNo = pSoldier->sGridNo + sXOffset + (MAXCOL * sYOffset);
|
||||
|
||||
if (!(sGridNo >= 0 && sGridNo < WORLD_MAX))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(gpWorldLevelData[sGridNo].uiFlags & MAPELEMENT_REACHABLE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sGridNo == pSoldier->pathing.sBlackList)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check roaming range
|
||||
if (iRoamRange < MAX_ROAMING_RANGE && !TileIsOutOfBounds(sOrigin))
|
||||
{
|
||||
iDistFromOrigin = SpacesAway(sOrigin, sGridNo);
|
||||
if (iDistFromOrigin > iRoamRange)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// exclude locations with tear/mustard gas (at this point, smoke is cool!)
|
||||
if (InGas(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip lighted spots
|
||||
if (InLightAtNight(sGridNo, pSoldier->pathing.bLevel) &&
|
||||
!InLightAtNight(pSoldier->sGridNo, pSoldier->pathing.bLevel))
|
||||
continue;
|
||||
|
||||
// skip deep water
|
||||
if (DeepWater(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip water
|
||||
if (Water(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid locations near fresh corpses
|
||||
if (!pSoldier->IsZombie() && GetNearestRottingCorpseAIWarning(sGridNo) > 0)
|
||||
//if (CorpseWarning(pSoldier, sGridNo, pSoldier->pathing.bLevel, TRUE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pSoldier->IsZombie() && NumberOfTeamMatesAdjacent(pSoldier, sGridNo) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CheckNPCDestination(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// avoid smoke
|
||||
/*if( InSmoke(sGridNo, pSoldier->pathing.bLevel, FALSE) )
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if (!LegalNPCDestination(pSoldier, sGridNo, IGNORE_PATH, NOWATER, 0))
|
||||
{
|
||||
continue; // skip on to the next potential grid
|
||||
}
|
||||
|
||||
// skip if too close to enemy
|
||||
//sClosestOpponent = ClosestKnownOpponent(pSoldier, NULL, NULL);
|
||||
sDistance = PythSpacesAway(sGridNo, sClosestOpponent);
|
||||
if (sDistance < (INT16)(DAY_VISION_RANGE / 2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip if this spot has no cover nearby
|
||||
if (!FindObstacleNearSpot(sGridNo, pSoldier->pathing.bLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!AnyCoverAtSpot(pSoldier, sGridNo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// check prone sight cover at spot
|
||||
/*if( !ProneSightCoverAtSpot(pSoldier, sGridNo) )
|
||||
{
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if (sDistance > sClosestDistance)
|
||||
{
|
||||
sBestSpot = sGridNo;
|
||||
sClosestDistance = sDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gubNPCAPBudget = 0;
|
||||
gubNPCDistLimit = 0;
|
||||
|
||||
return(sBestSpot);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<ClCompile Include="PanicButtons.cpp" />
|
||||
<ClCompile Include="QuestDebug.cpp" />
|
||||
<ClCompile Include="Realtime.cpp" />
|
||||
<ClCompile Include="ZombieDecideAction.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B369A125-E62E-46AE-9285-58003D688301}</ProjectGuid>
|
||||
|
||||
@@ -71,5 +71,8 @@
|
||||
<ClCompile Include="Realtime.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZombieDecideAction.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -45,6 +45,7 @@
|
||||
<ClCompile Include="PanicButtons.cpp" />
|
||||
<ClCompile Include="QuestDebug.cpp" />
|
||||
<ClCompile Include="Realtime.cpp" />
|
||||
<ClCompile Include="ZombieDecideAction.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B369A125-E62E-46AE-9285-58003D688301}</ProjectGuid>
|
||||
|
||||
@@ -71,5 +71,8 @@
|
||||
<ClCompile Include="Realtime.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ZombieDecideAction.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -45,6 +45,7 @@
|
||||
<ClCompile Include="PanicButtons.cpp" />
|
||||
<ClCompile Include="QuestDebug.cpp" />
|
||||
<ClCompile Include="Realtime.cpp" />
|
||||
<ClCompile Include="ZombieDecideAction.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B369A125-E62E-46AE-9285-58003D688301}</ProjectGuid>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+53
-4
@@ -5,6 +5,7 @@
|
||||
#include "worlddef.h"
|
||||
#include "Soldier Control.h"
|
||||
#include "Isometric Utils.h"
|
||||
#include "Rotting Corpses.h"
|
||||
|
||||
#define TESTAICONTROL
|
||||
|
||||
@@ -109,6 +110,7 @@ typedef enum
|
||||
AI_ACTION_DOCTOR_SELF, // added by Flugente: AI-ONLY! bandage/surgery on self. DO NOT USE THIS FOR MERCS!!!
|
||||
AI_ACTION_SELFDETONATE, // added by Flugente: blow up an explosive in own inventory
|
||||
AI_ACTION_STOP_MEDIC, // sevenfm: stop giving aid animation
|
||||
AI_ACTION_LAST = AI_ACTION_STOP_MEDIC
|
||||
} ActionType;
|
||||
|
||||
|
||||
@@ -153,6 +155,12 @@ enum QuoteActionType
|
||||
|
||||
extern INT8 gbDiff[MAX_DIFF_PARMS][5];
|
||||
|
||||
enum{
|
||||
ADVANCE_SPOT_SIGHT_COVER,
|
||||
ADVANCE_SPOT_PRONE_COVER,
|
||||
ADVANCE_SPOT_ANY_COVER
|
||||
};
|
||||
|
||||
void ActionDone(SOLDIERTYPE *pSoldier);
|
||||
INT16 ActionInProgress(SOLDIERTYPE *pSoldier);
|
||||
|
||||
@@ -173,7 +181,9 @@ INT32 ClosestUnDisguisedPC( SOLDIERTYPE *pSoldier, INT32 * psDistance ); // Flug
|
||||
BOOLEAN CanAutoBandage( BOOLEAN fDoFullCheck );
|
||||
|
||||
void DebugAI( STR szOutput );
|
||||
INT8 DecideAction(SOLDIERTYPE *pSoldier);
|
||||
enum { AI_MSG_START, AI_MSG_DECIDE, AI_MSG_INFO, AI_MSG_TOPIC };
|
||||
void DebugAI(INT8 bMsgType, SOLDIERTYPE *pSoldier, STR szOutput, INT8 bAction = -1);
|
||||
INT8 DecideAction(SOLDIERTYPE *pSoldier);
|
||||
INT8 DecideActionBlack(SOLDIERTYPE *pSoldier);
|
||||
INT8 DecideActionEscort(SOLDIERTYPE *pSoldier);
|
||||
INT8 DecideActionGreen(SOLDIERTYPE *pSoldier);
|
||||
@@ -293,8 +303,13 @@ BOOLEAN AICheckIsFlanking( SOLDIERTYPE *pSoldier );
|
||||
|
||||
INT8 CalcMoraleNew(SOLDIERTYPE *pSoldier);
|
||||
|
||||
BOOLEAN ProneSightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
|
||||
BOOLEAN SightCoverAtSpot( SOLDIERTYPE *pSoldier, INT32 sSpot );
|
||||
BOOLEAN ProneSightCoverAtSpot(SOLDIERTYPE *pSoldier, INT32 sSpot, BOOLEAN fUnlimited);
|
||||
BOOLEAN SightCoverAtSpot(SOLDIERTYPE *pSoldier, INT32 sSpot, BOOLEAN fUnlimited);
|
||||
BOOLEAN AnyCoverAtSpot(SOLDIERTYPE *pSoldier, INT32 sSpot);
|
||||
BOOLEAN AnyCoverFromSpot(INT32 sSpot, INT8 bLevel, INT32 sThreatLoc, INT8 bThreatLevel);
|
||||
|
||||
INT32 FindAdvanceSpot(SOLDIERTYPE *pSoldier, INT32 sTargetSpot, INT8 bAction, UINT8 ubType, BOOLEAN fUnlimited);
|
||||
INT32 FindRetreatSpot(SOLDIERTYPE *pSoldier);
|
||||
|
||||
BOOLEAN CheckDoorAtGridno(UINT32 usGridNo);
|
||||
BOOLEAN CheckDoorNearGridno(UINT32 usGridNo);
|
||||
@@ -307,19 +322,53 @@ BOOLEAN FindNearbyExplosiveStructure(INT32 sSpot, INT8 bLevel);
|
||||
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 );
|
||||
|
||||
BOOLEAN FindObstacleNearSpot(INT32 sSpot, INT8 bLevel);
|
||||
|
||||
BOOLEAN CheckNPCDestination(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
||||
UINT8 SpotDangerLevel(SOLDIERTYPE *pSoldier, INT32 sGridNo);
|
||||
BOOLEAN AllowDeepWaterFlanking(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckUnderground(void);
|
||||
|
||||
BOOLEAN CorpseWarning(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel);
|
||||
BOOLEAN CorpseEnemyTeam(ROTTING_CORPSE *pCorpse);
|
||||
BOOLEAN CorpseMilitiaTeam(ROTTING_CORPSE *pCorpse);
|
||||
|
||||
BOOLEAN NorthSpot(INT32 sSpot, INT8 bLevel);
|
||||
BOOLEAN SoldierAI(SOLDIERTYPE *pSoldier);
|
||||
|
||||
UINT8 AIDirection(INT32 sSpot1, INT32 sSpot2);
|
||||
|
||||
BOOLEAN AIGunScoped(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AIGunInHandScoped(SOLDIERTYPE *pSoldier);
|
||||
UINT16 AIGunRange(SOLDIERTYPE *pSoldier); // gun range in tiles
|
||||
UINT16 AIGunClass(SOLDIERTYPE *pSoldier);
|
||||
UINT16 AIGunType(SOLDIERTYPE *pSoldier);
|
||||
UINT16 AIGunAmmo(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AIGunAutofireCapable(SOLDIERTYPE *pSoldier);
|
||||
UINT8 AIGunDeadliness(SOLDIERTYPE *pSoldier);
|
||||
|
||||
BOOLEAN AICheckNVG(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckHasWeaponOfType(SOLDIERTYPE *pSoldier, UINT8 ubWeaponType);
|
||||
BOOLEAN AICheckHasGun(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckShortWeaponRange(SOLDIERTYPE *pSoldier);
|
||||
|
||||
BOOLEAN AICheckIsSniper(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsMarksman(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsMachinegunner(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsRadioOperator(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsMedic(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsMortarOperator(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsGLOperator(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsOfficer(SOLDIERTYPE *pSoldier);
|
||||
BOOLEAN AICheckIsCommander(SOLDIERTYPE *pSoldier);
|
||||
|
||||
#define MAX_FLANKS_RED 25
|
||||
#define MAX_FLANKS_YELLOW 25
|
||||
|
||||
#define MAX_TILES_MOVE_TURN (APBPConstants[AP_MAXIMUM] / (APBPConstants[AP_MOVEMENT_FLAT] + APBPConstants[AP_MODIFIER_RUN]))
|
||||
|
||||
// vision range defines
|
||||
#define DAY_VISION_RANGE (gGameExternalOptions.ubStraightSightRange * STRAIGHT_RATIO * 2)
|
||||
#define NIGHT_VISION_RANGE (gGameExternalOptions.ubStraightSightRange * STRAIGHT_RATIO )
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include "Campaign Types.h"
|
||||
#include "Tactical Save.h"
|
||||
#include "strategicmap.h"
|
||||
// sevenfm
|
||||
#include "environment.h"
|
||||
#include "Render Fun.h"
|
||||
#endif
|
||||
|
||||
#include "SaveLoadGame.h"
|
||||
@@ -1188,6 +1191,34 @@ BOOL GetRandomSignalSmokeGridNo(INT32* psGridNo)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// sevenfm: check smoke effect of certain type at gridno
|
||||
BOOLEAN CheckSmokeEffect(INT32 sGridNo, INT8 bLevel, INT8 bType)
|
||||
{
|
||||
UINT32 uiCnt;
|
||||
INT8 bSmokeEffectLevel;
|
||||
|
||||
//loop through all smoke effects
|
||||
for (uiCnt = 0; uiCnt < guiNumSmokeEffects; uiCnt++)
|
||||
{
|
||||
if (gSmokeEffectData[uiCnt].fAllocated &&
|
||||
gSmokeEffectData[uiCnt].sGridNo == sGridNo &&
|
||||
gSmokeEffectData[uiCnt].bType == bType)
|
||||
{
|
||||
if (gSmokeEffectData[uiCnt].bFlags & SMOKE_EFFECT_ON_ROOF)
|
||||
bSmokeEffectLevel = 1;
|
||||
else
|
||||
bSmokeEffectLevel = 0;
|
||||
|
||||
if (bSmokeEffectLevel == bLevel)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN FindVisibleSmokeEffect(INT8 bType)
|
||||
{
|
||||
UINT32 uiCnt;
|
||||
|
||||
@@ -71,6 +71,8 @@ void UpdateSmokeEffectGraphics( );
|
||||
// Flugente: get the gridno and blevel of a random smoke signal, if one exists
|
||||
BOOL GetRandomSignalSmokeGridNo(INT32* psGridNo);
|
||||
|
||||
// sevenfm: check if smoke effect of certain type is present at gridno
|
||||
BOOLEAN CheckSmokeEffect(INT32 sGridNo, INT8 bLevel, INT8 bType);
|
||||
// find smoke effect on visible screen
|
||||
BOOLEAN FindVisibleSmokeEffect(INT8 bType);
|
||||
|
||||
|
||||
+20
-3
@@ -793,6 +793,7 @@ void PhysicsDeleteObject( REAL_OBJECT *pObject )
|
||||
}
|
||||
}
|
||||
|
||||
INT16 gsWaterSplashSoundNum = -1;
|
||||
|
||||
BOOLEAN PhysicsCheckForCollisions( REAL_OBJECT *pObject, INT32 *piCollisionID )
|
||||
{
|
||||
@@ -1113,9 +1114,25 @@ BOOLEAN PhysicsCheckForCollisions( REAL_OBJECT *pObject, INT32 *piCollisionID )
|
||||
|
||||
// sevenfm: also play sound
|
||||
CHAR8 zFilename[512];
|
||||
sprintf(zFilename, "sounds\\misc\\Splash%d.ogg", Random(3) + 1);
|
||||
if (FileExists(zFilename))
|
||||
PlayJA2SampleFromFile(zFilename, RATE_11025, SoundVolume(MIDVOLUME, pObject->sGridNo), 1, SoundDir(pObject->sGridNo));
|
||||
// prepare water splash sound
|
||||
if (gsWaterSplashSoundNum < 0)
|
||||
{
|
||||
gsWaterSplashSoundNum = 0;
|
||||
do
|
||||
{
|
||||
gsWaterSplashSoundNum++;
|
||||
sprintf(zFilename, "sounds\\misc\\Splash%d.ogg", gsWaterSplashSoundNum);
|
||||
} while (FileExists(zFilename));
|
||||
gsWaterSplashSoundNum--;
|
||||
}
|
||||
if (gsWaterSplashSoundNum > 0)
|
||||
{
|
||||
sprintf(zFilename, "sounds\\misc\\Splash%d.ogg", Random(gsWaterSplashSoundNum) + 1);
|
||||
if (FileExists(zFilename))
|
||||
{
|
||||
PlayJA2SampleFromFile(zFilename, RATE_11025, SoundVolume(MIDVOLUME, pObject->sGridNo), 1, SoundDir(pObject->sGridNo));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user