mirror of
https://github.com/1dot13/source.git
synced 2026-09-02 14:36:06 +02:00
Further refinement of new ModularizedTacticalAI architecture; added plans for Crows
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6017 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
#include "random.h"
|
||||
#include "Points.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
extern BOOLEAN gfTurnBasedAI;
|
||||
|
||||
@@ -104,6 +107,14 @@ enum
|
||||
#undef max
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
// Added by feynman - remove all the ugly #ifdefs printf combinations for required for DebugAI
|
||||
//#define DEBUGAI
|
||||
#ifdef DEBUGAI
|
||||
#define DEBUGAIMSG(X) std::cerr<<"AIDEBUGMSG "<<std::setw(40)<<__FILE__<<":"<<std::setw(4)<<__LINE__<<": "<< X<<std::endl
|
||||
#else
|
||||
#define DEBUGAIMSG(X)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SOLDIERTYPE * pOpponent;
|
||||
|
||||
+12
-33
@@ -63,8 +63,6 @@
|
||||
#include "ModularizedTacticalAI/include/Plan.h"
|
||||
#include "ModularizedTacticalAI/include/PlanFactoryLibrary.h"
|
||||
#include "ModularizedTacticalAI/include/AbstractPlanFactory.h"
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef JA2UB
|
||||
#include "Ja25_Tactical.h"
|
||||
@@ -500,19 +498,10 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named
|
||||
|
||||
gubAICounter++;
|
||||
|
||||
if(!pSoldier->ai_masterplan_) // if the Soldier has no plan, create one
|
||||
{
|
||||
if(pSoldier->bAIIndex == 0) // not yet initialized, use bTeam+1 as default
|
||||
pSoldier->bAIIndex = pSoldier->bTeam + 1;
|
||||
AI::tactical::AIInputData ai_input;
|
||||
ai_input.npc_to_plan_for_ = pSoldier;
|
||||
AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
|
||||
pSoldier->ai_masterplan_ = plan_lib->create_plan(pSoldier->bAIIndex, ai_input);
|
||||
}
|
||||
|
||||
AI::tactical::PlanInputData plan_input;
|
||||
plan_input.controlled_npc_ = pSoldier;
|
||||
pSoldier->ai_masterplan_->execute(gfTurnBasedAI, plan_input);
|
||||
if(gfTurnBasedAI)
|
||||
TurnBasedHandleNPCAI(pSoldier);
|
||||
else
|
||||
RTHandleAI( pSoldier );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1445,26 +1434,16 @@ void TurnBasedHandleNPCAI(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
if (!(gTacticalStatus.uiFlags & ENGAGED_IN_CONV))
|
||||
{
|
||||
#ifdef ENABLE_ZOMBIES
|
||||
if ( pSoldier->IsZombie() )
|
||||
{
|
||||
pSoldier->aiData.bAction = ZombieDecideAction(pSoldier);
|
||||
}
|
||||
else if (CREATURE_OR_BLOODCAT( pSoldier ))
|
||||
#else
|
||||
if (CREATURE_OR_BLOODCAT( pSoldier ))
|
||||
#endif
|
||||
if(!pSoldier->ai_masterplan_) // if the Soldier has no plan, create one
|
||||
{
|
||||
pSoldier->aiData.bAction = CreatureDecideAction( pSoldier );
|
||||
}
|
||||
else if (pSoldier->ubBodyType == CROW)
|
||||
{
|
||||
pSoldier->aiData.bAction = CrowDecideAction( pSoldier );
|
||||
}
|
||||
else
|
||||
{
|
||||
pSoldier->aiData.bAction = DecideAction(pSoldier);
|
||||
if(pSoldier->bAIIndex == 0) // not yet initialized, use bTeam+1 as default
|
||||
pSoldier->bAIIndex = pSoldier->bTeam + 1;
|
||||
AI::tactical::AIInputData ai_input;
|
||||
AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
|
||||
pSoldier->ai_masterplan_ = plan_lib->create_plan(pSoldier->bAIIndex, pSoldier, ai_input);
|
||||
}
|
||||
AI::tactical::PlanInputData plan_input(true, gTacticalStatus);
|
||||
pSoldier->ai_masterplan_->execute(plan_input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1670,91 +1670,3 @@ void CreatureDecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
INT8 CrowDecideActionRed( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
// OK, Fly away!
|
||||
//HandleCrowFlyAway( pSoldier );
|
||||
if (!gfTurnBasedAI)
|
||||
{
|
||||
pSoldier->aiData.usActionData = 30000;
|
||||
return( AI_ACTION_WAIT );
|
||||
}
|
||||
else
|
||||
{
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INT8 CrowDecideActionGreen( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
INT32 sCorpseGridNo;
|
||||
UINT8 ubDirection;
|
||||
INT16 sFacingDir;
|
||||
|
||||
// Look for a corse!
|
||||
sCorpseGridNo = FindNearestRottingCorpse( pSoldier );
|
||||
|
||||
if (!TileIsOutOfBounds(sCorpseGridNo))
|
||||
{
|
||||
// Are we close, if so , peck!
|
||||
if ( SpacesAway( pSoldier->sGridNo, sCorpseGridNo ) < 2 )
|
||||
{
|
||||
// Change facing
|
||||
sFacingDir = GetDirectionFromGridNo( sCorpseGridNo, pSoldier );
|
||||
|
||||
if ( sFacingDir != pSoldier->ubDirection )
|
||||
{
|
||||
pSoldier->aiData.usActionData = sFacingDir;
|
||||
return(AI_ACTION_CHANGE_FACING);
|
||||
}
|
||||
else if (!gfTurnBasedAI)
|
||||
{
|
||||
pSoldier->aiData.usActionData = 30000;
|
||||
return( AI_ACTION_WAIT );
|
||||
}
|
||||
else
|
||||
{
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Walk to nearest one!
|
||||
pSoldier->aiData.usActionData = FindGridNoFromSweetSpot( pSoldier, sCorpseGridNo, 4, &ubDirection );
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData))
|
||||
{
|
||||
return( AI_ACTION_GET_CLOSER );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
|
||||
INT8 CrowDecideAction( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
if ( pSoldier->usAnimState == CROW_FLY )
|
||||
{
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
|
||||
switch( pSoldier->aiData.bAlertStatus )
|
||||
{
|
||||
case STATUS_GREEN:
|
||||
case STATUS_YELLOW:
|
||||
return( CrowDecideActionGreen( pSoldier ) );
|
||||
|
||||
case STATUS_RED:
|
||||
case STATUS_BLACK:
|
||||
return( CrowDecideActionRed( pSoldier ) );
|
||||
|
||||
default:
|
||||
Assert( FALSE );
|
||||
return( AI_ACTION_NONE );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5766,163 +5766,6 @@ INT16 ubMinAPCost;
|
||||
|
||||
}
|
||||
|
||||
INT8 DecideAction(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideAction");
|
||||
INT8 bAction=AI_ACTION_NONE;
|
||||
#ifdef DEBUGDECISIONS
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
|
||||
#ifdef AI_TIMING_TESTS
|
||||
UINT32 uiStartTime, uiEndTime;
|
||||
#endif
|
||||
|
||||
if ( pSoldier->bTeam != MILITIA_TEAM )
|
||||
{
|
||||
if ( !sniperwarning && pSoldier->aiData.bOrders == SNIPER )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_WATHCHOUTFORSNIPERS] );
|
||||
sniperwarning = TRUE;
|
||||
}
|
||||
|
||||
if (!biggunwarning && FindRocketLauncherOrCannon(pSoldier) != NO_SLOT )
|
||||
{
|
||||
biggunwarning = TRUE;
|
||||
//TODO: don't say this again after reloading a savegame
|
||||
SayQuoteFromAnyBodyInSector( QUOTE_WEARY_SLASH_SUSPUCIOUS );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// turn off cautious flag
|
||||
pSoldier->aiData.fAIFlags &= (~AI_CAUTIOUS);
|
||||
//reset flank count
|
||||
|
||||
//NumMessage("DecideAction - Guy#",pSoldier->ubID);
|
||||
|
||||
// if the NPC is being "ESCORTED" (seen civilians only for now)
|
||||
if (pSoldier->aiData.bUnderEscort)
|
||||
{
|
||||
#ifdef DEBUGDECISIONS
|
||||
AIPopMessage("AlertStatus = ESCORT");
|
||||
#endif
|
||||
|
||||
//bAction = DecideActionEscort(pSoldier);
|
||||
}
|
||||
else // "normal" NPC AI
|
||||
{
|
||||
// if status over-ride is set, bypass RED/YELLOW and go directly to GREEN!
|
||||
if ((pSoldier->aiData.bBypassToGreen) && (pSoldier->aiData.bAlertStatus < STATUS_BLACK))
|
||||
{
|
||||
bAction = DecideActionGreen(pSoldier);
|
||||
if ( !gfTurnBasedAI )
|
||||
{
|
||||
// reset bypass now
|
||||
pSoldier->aiData.bBypassToGreen = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (pSoldier->aiData.bAlertStatus)
|
||||
{
|
||||
case STATUS_GREEN:
|
||||
#ifdef DEBUGDECISIONS
|
||||
AIPopMessage("AlertStatus = GREEN");
|
||||
#endif
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiStartTime = GetJA2Clock();
|
||||
#endif
|
||||
bAction = DecideActionGreen(pSoldier);
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiEndTime = GetJA2Clock();
|
||||
guiGreenTimeTotal += (uiEndTime - uiStartTime);
|
||||
guiGreenCounter++;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case STATUS_YELLOW:
|
||||
#ifdef DEBUGDECISIONS
|
||||
AIPopMessage("AlertStatus = YELLOW");
|
||||
#endif
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiStartTime = GetJA2Clock();
|
||||
#endif
|
||||
bAction = DecideActionYellow(pSoldier);
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiEndTime = GetJA2Clock();
|
||||
guiYellowTimeTotal += (uiEndTime - uiStartTime);
|
||||
guiYellowCounter++;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case STATUS_RED:
|
||||
#ifdef DEBUGDECISIONS
|
||||
AIPopMessage("AlertStatus = RED");
|
||||
#endif
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiStartTime = GetJA2Clock();
|
||||
#endif
|
||||
bAction = DecideActionRed(pSoldier,TRUE);
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiEndTime = GetJA2Clock();
|
||||
guiRedTimeTotal += (uiEndTime - uiStartTime);
|
||||
guiRedCounter++;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case STATUS_BLACK:
|
||||
#ifdef DEBUGDECISIONS
|
||||
AIPopMessage("AlertStatus = BLACK");
|
||||
#endif
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiStartTime = GetJA2Clock();
|
||||
#endif
|
||||
bAction = DecideActionBlack(pSoldier);
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("DecideActionBlack=%d",bAction));
|
||||
#ifdef AI_TIMING_TESTS
|
||||
uiEndTime = GetJA2Clock();
|
||||
guiBlackTimeTotal += (uiEndTime - uiStartTime);
|
||||
guiBlackCounter++;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
sprintf( tempstr,"DecideAction: selected action %d, actionData %d\n\n",bAction,pSoldier->aiData.usActionData);
|
||||
DebugAI( tempstr );
|
||||
#endif
|
||||
|
||||
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"DecideAction done");
|
||||
|
||||
return(bAction);
|
||||
}
|
||||
|
||||
INT8 DecideActionEscort(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
#ifdef DEBUGDECISIONS
|
||||
STR16 tempstr;
|
||||
#endif
|
||||
|
||||
// if he has a place to go, and isn't already there... go!
|
||||
if (!TileIsOutOfBounds(pSoldier->aiData.usActionData) && (pSoldier->sGridNo != pSoldier->aiData.usActionData))
|
||||
{
|
||||
#ifdef DEBUGDECISIONS
|
||||
sprintf(tempstr,"%s - ESCORTED NPC GOING to grid %d",pSoldier->name,pSoldier->aiData.usActionData);
|
||||
AIPopMessage(tempstr);
|
||||
#endif
|
||||
|
||||
return(AI_ACTION_ESCORTED_MOVE);
|
||||
}
|
||||
else
|
||||
return(AI_ACTION_NONE);
|
||||
}
|
||||
|
||||
|
||||
void DecideAlertStatus( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
#ifdef DEBUGDECISIONS
|
||||
|
||||
+14
-65
@@ -19,71 +19,11 @@
|
||||
#include "Quests.h"
|
||||
#include "GameSettings.h"
|
||||
#endif
|
||||
// needed to use the modularized tactical AI:
|
||||
#include "ModularizedTacticalAI/include/Plan.h"
|
||||
#include "ModularizedTacticalAI/include/PlanFactoryLibrary.h"
|
||||
#include "ModularizedTacticalAI/include/AbstractPlanFactory.h"
|
||||
|
||||
INT8 RTPlayerDecideAction( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
INT8 bAction=AI_ACTION_NONE;
|
||||
|
||||
if (gTacticalStatus.fAutoBandageMode)
|
||||
{
|
||||
bAction = DecideAutoBandage( pSoldier );
|
||||
}
|
||||
#ifdef ENABLE_ZOMBIES
|
||||
else if ( pSoldier->IsZombie() )
|
||||
{
|
||||
bAction = ZombieDecideAction( pSoldier );
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
bAction = DecideAction( pSoldier );
|
||||
}
|
||||
|
||||
#ifdef DEBUGDECISIONS
|
||||
STR tempstr;
|
||||
sprintf(tempstr,"DecideAction: selected action %d, actionData %d\n\n",bAction,pSoldier->aiData.usActionData);
|
||||
DebugAI( tempstr );
|
||||
#endif
|
||||
|
||||
return(bAction);
|
||||
}
|
||||
|
||||
INT8 RTDecideAction(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
if (CREATURE_OR_BLOODCAT( pSoldier ) )
|
||||
{
|
||||
return( CreatureDecideAction( pSoldier ) );
|
||||
}
|
||||
#ifdef ENABLE_ZOMBIES
|
||||
else if ( pSoldier->IsZombie() )
|
||||
{
|
||||
return( ZombieDecideAction( pSoldier ) );
|
||||
}
|
||||
#endif
|
||||
else if (pSoldier->ubBodyType == CROW)
|
||||
{
|
||||
return( CrowDecideAction( pSoldier ) );
|
||||
}
|
||||
else if (pSoldier->bTeam == gbPlayerNum)
|
||||
{
|
||||
return( RTPlayerDecideAction( pSoldier ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// handle traversal
|
||||
if ( (pSoldier->ubProfile != NO_PROFILE) && (gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags3 & PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL ) )
|
||||
{
|
||||
TriggerNPCWithGivenApproach( pSoldier->ubProfile, APPROACH_DONE_TRAVERSAL, FALSE );
|
||||
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags3 &= (~PROFILE_MISC_FLAG3_HANDLE_DONE_TRAVERSAL);
|
||||
pSoldier->ubQuoteActionID = 0;
|
||||
// wait a tiny bit
|
||||
pSoldier->aiData.usActionData = 100;
|
||||
return( AI_ACTION_WAIT );
|
||||
}
|
||||
|
||||
return( DecideAction( pSoldier ) );
|
||||
}
|
||||
}
|
||||
|
||||
UINT16 RealtimeDelay( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
@@ -236,7 +176,16 @@ void RTHandleAI( SOLDIERTYPE * pSoldier )
|
||||
{
|
||||
if (!(gTacticalStatus.uiFlags & ENGAGED_IN_CONV))
|
||||
{
|
||||
pSoldier->aiData.bAction = RTDecideAction( pSoldier );
|
||||
if(!pSoldier->ai_masterplan_) // if the Soldier has no plan, create one
|
||||
{
|
||||
if(pSoldier->bAIIndex == 0) // not yet initialized, use bTeam+1 as default
|
||||
pSoldier->bAIIndex = pSoldier->bTeam + 1;
|
||||
AI::tactical::AIInputData ai_input;
|
||||
AI::tactical::PlanFactoryLibrary* plan_lib(AI::tactical::PlanFactoryLibrary::instance());
|
||||
pSoldier->ai_masterplan_ = plan_lib->create_plan(pSoldier->bAIIndex, pSoldier, ai_input);
|
||||
}
|
||||
AI::tactical::PlanInputData plan_input(false, gTacticalStatus);
|
||||
pSoldier->ai_masterplan_->execute(plan_input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user