mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-04-20 16:32:30 +03:00
Shadow Walker: Added 'ambush' state to improve squad behavior.
This commit is contained in:
parent
64841073d9
commit
91556205fb
@ -17,6 +17,7 @@
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "basehlcombatweapon_shared.h"
|
||||
#include "ai_squadslot.h"
|
||||
#include "ai_squad.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
@ -48,6 +49,7 @@ BEGIN_DATADESC(CNPC_BaseCustomNPC)
|
||||
DEFINE_KEYFIELD(m_bCannotOpenDoors, FIELD_BOOLEAN, "CannotOpenDoors"),
|
||||
DEFINE_KEYFIELD(m_bCanPickupWeapons, FIELD_BOOLEAN, "CanPickupWeapons"),
|
||||
|
||||
DEFINE_FIELD(m_iNumSquadmates, FIELD_INTEGER),
|
||||
DEFINE_FIELD(m_bWanderToggle, FIELD_BOOLEAN),
|
||||
DEFINE_FIELD(m_flNextSoundTime, FIELD_TIME),
|
||||
DEFINE_FIELD(m_flNextFoundEnemySoundTime, FIELD_TIME),
|
||||
@ -245,6 +247,54 @@ int CNPC_BaseCustomNPC::SelectScheduleRetrieveItem()
|
||||
return SCHED_NONE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Select ideal state.
|
||||
// Conditions for custom states are defined here.
|
||||
//-----------------------------------------------------------------------------
|
||||
NPC_STATE CNPC_BaseCustomNPC::SelectIdealState(void)
|
||||
{
|
||||
switch ((int)this->m_NPCState) {
|
||||
case NPC_STATE_AMBUSH:
|
||||
return SelectAmbushIdealState();
|
||||
case NPC_STATE_SURRENDER:
|
||||
return SelectSurrenderIdealState();
|
||||
default:
|
||||
return BaseClass::SelectIdealState();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NPC_STATE CNPC_BaseCustomNPC::SelectAmbushIdealState()
|
||||
{
|
||||
// AMBUSH goes to ALERT upon death of enemy
|
||||
if (GetEnemy() == NULL)
|
||||
{
|
||||
return NPC_STATE_ALERT;
|
||||
}
|
||||
|
||||
// If I am not in a squad, there is no reason to ambush
|
||||
if (!m_pSquad) {
|
||||
return NPC_STATE_COMBAT;
|
||||
}
|
||||
|
||||
// If I am the last in a squad, attack!
|
||||
if (m_pSquad->NumMembers() == 1) {
|
||||
return NPC_STATE_COMBAT;
|
||||
}
|
||||
|
||||
if (OccupyStrategySlotRange(SQUAD_SLOT_CHASE_1, SQUAD_SLOT_CHASE_2)) {
|
||||
return NPC_STATE_COMBAT;
|
||||
}
|
||||
|
||||
// The best ideal state is the current ideal state.
|
||||
return (NPC_STATE)NPC_STATE_AMBUSH;
|
||||
}
|
||||
|
||||
NPC_STATE CNPC_BaseCustomNPC::SelectSurrenderIdealState()
|
||||
{
|
||||
return NPC_STATE_ALERT;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Select a schedule to retrieve better weapons if they are available.
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -265,7 +315,7 @@ int CNPC_BaseCustomNPC::SelectScheduleWander()
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectSchedule()
|
||||
{
|
||||
switch (m_NPCState)
|
||||
switch ((int)m_NPCState)
|
||||
{
|
||||
case NPC_STATE_IDLE:
|
||||
AssertMsgOnce(GetEnemy() == NULL, "NPC has enemy but is not in combat state?");
|
||||
@ -277,7 +327,10 @@ int CNPC_BaseCustomNPC::SelectSchedule()
|
||||
|
||||
case NPC_STATE_COMBAT:
|
||||
return SelectCombatSchedule();
|
||||
|
||||
case NPC_STATE_AMBUSH:
|
||||
return SelectAmbushSchedule();
|
||||
case NPC_STATE_SURRENDER:
|
||||
return SelectSurrenderSchedule();
|
||||
default:
|
||||
return BaseClass::SelectSchedule();
|
||||
}
|
||||
@ -361,6 +414,66 @@ int CNPC_BaseCustomNPC::SelectCombatSchedule()
|
||||
return BaseClass::SelectSchedule(); // Let Base NPC handle it
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Combat schedule selection
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectAmbushSchedule()
|
||||
{
|
||||
// Check enemy death
|
||||
if (HasCondition(COND_ENEMY_DEAD))
|
||||
{
|
||||
// clear the current (dead) enemy and try to find another.
|
||||
SetEnemy(NULL);
|
||||
|
||||
if (ChooseEnemy())
|
||||
{
|
||||
SetState(NPC_STATE_COMBAT);
|
||||
FoundEnemySound();
|
||||
ClearCondition(COND_ENEMY_DEAD);
|
||||
return SelectSchedule();
|
||||
}
|
||||
|
||||
SetState(NPC_STATE_ALERT);
|
||||
return SelectSchedule();
|
||||
}
|
||||
|
||||
|
||||
CBaseEntity* pEnemy = GetEnemy();
|
||||
if (pEnemy && EnemyDistance(pEnemy) < 128)
|
||||
{
|
||||
SetState(NPC_STATE_COMBAT);
|
||||
return SelectSchedule();
|
||||
}
|
||||
|
||||
if (pEnemy == NULL || HasCondition(COND_LOST_ENEMY)) {
|
||||
SetState(NPC_STATE_ALERT);
|
||||
return SelectSchedule();
|
||||
}
|
||||
|
||||
// If I am the last in a squad, attack!
|
||||
if (m_iNumSquadmates > m_pSquad->NumMembers())
|
||||
SetState(SelectAmbushIdealState());
|
||||
|
||||
if (HasCondition(COND_LIGHT_DAMAGE)) {
|
||||
SetState(NPC_STATE_COMBAT);
|
||||
}
|
||||
|
||||
if (HasCondition(COND_SEE_ENEMY) && HasCondition(COND_ENEMY_FACING_ME) && HasCondition(COND_HAVE_ENEMY_LOS)) {
|
||||
if(GetState() != NPC_STATE_COMBAT)
|
||||
SetState(SelectAmbushIdealState());
|
||||
return SCHED_HIDE;
|
||||
}
|
||||
|
||||
m_iNumSquadmates = m_pSquad->NumMembers();
|
||||
|
||||
return SCHED_COMBAT_FACE;
|
||||
}
|
||||
|
||||
int CNPC_BaseCustomNPC::SelectSurrenderSchedule()
|
||||
{
|
||||
return BaseClass::SelectSchedule();
|
||||
}
|
||||
|
||||
bool CNPC_BaseCustomNPC::HasRangedWeapon()
|
||||
{
|
||||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||||
|
@ -29,6 +29,28 @@ enum
|
||||
LAST_BASE_CUSTOM_SCHED
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
// states
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
NPC_STATE_FIRST = NPC_STATE_DEAD,
|
||||
NPC_STATE_AMBUSH,
|
||||
NPC_STATE_SURRENDER,
|
||||
NPC_STATE_LAST_CUSTOM
|
||||
};
|
||||
|
||||
// -----------------------------------------------
|
||||
// Squad slots
|
||||
// -----------------------------------------------
|
||||
enum
|
||||
{
|
||||
LAST_SQUADSLOT = 100, // Custom NPCs might share a squad with any NPC, so let's just be safe and skip to a high number
|
||||
SQUAD_SLOT_CHASE_1,
|
||||
SQUAD_SLOT_CHASE_2,
|
||||
LAST_CUSTOM_SQUADSLOT
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
typedef CAI_BlendingHost< CAI_BehaviorHost<CAI_BaseNPC> > CAI_CustomNPCBase;
|
||||
@ -48,10 +70,17 @@ public:
|
||||
virtual int SelectIdleSchedule();
|
||||
virtual int SelectAlertSchedule();
|
||||
virtual int SelectCombatSchedule();
|
||||
virtual int SelectAmbushSchedule();
|
||||
virtual int SelectSurrenderSchedule();
|
||||
virtual float GetSequenceGroundSpeed(CStudioHdr *pStudioHdr, int iSequence);
|
||||
virtual Activity NPC_TranslateActivity(Activity eNewActivity);
|
||||
virtual int TranslateSchedule(int scheduleType);
|
||||
|
||||
// Custom states
|
||||
virtual NPC_STATE SelectIdealState(void);
|
||||
NPC_STATE SelectAmbushIdealState();
|
||||
NPC_STATE SelectSurrenderIdealState();
|
||||
|
||||
// Sounds
|
||||
virtual void PlaySound(string_t soundname, bool optional);
|
||||
virtual void DeathSound(const CTakeDamageInfo &info) { PlaySound(m_iszDeathSound, true); }
|
||||
@ -90,7 +119,7 @@ protected:
|
||||
bool HasRangedWeapon();
|
||||
void PrecacheNPCSoundScript(string_t* SoundName, string_t defaultSoundName);
|
||||
|
||||
|
||||
int m_iNumSquadmates;
|
||||
bool m_bUseBothSquadSlots; // If true use two squad slots, if false use one squad slot
|
||||
bool m_bCannotOpenDoors; // If true, this NPC cannot open doors. The condition is reversed because originally it could.
|
||||
bool m_bCanPickupWeapons; // If true, this NPC is able to pick up weapons off of the ground just like npc_citizen.
|
||||
|
@ -186,30 +186,6 @@ int CNPC_ShadowWalker::SelectFailSchedule(int failedSchedule, int failedTask, AI
|
||||
return BaseClass::SelectFailSchedule(failedSchedule, failedTask, taskFailCode);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Select a schedule to execute based on conditions.
|
||||
// This is the most critical AI method.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_ShadowWalker::SelectSchedule()
|
||||
{
|
||||
switch (m_NPCState)
|
||||
{
|
||||
case NPC_STATE_IDLE:
|
||||
AssertMsgOnce(GetEnemy() == NULL, "NPC has enemy but is not in combat state?");
|
||||
return SelectIdleSchedule();
|
||||
|
||||
case NPC_STATE_ALERT:
|
||||
AssertMsgOnce(GetEnemy() == NULL, "NPC has enemy but is not in combat state?");
|
||||
return SelectAlertSchedule();
|
||||
|
||||
case NPC_STATE_COMBAT:
|
||||
return SelectCombatSchedule();
|
||||
|
||||
default:
|
||||
return BaseClass::SelectSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Idle schedule selection
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -305,7 +281,6 @@ int CNPC_ShadowWalker::SelectCombatSchedule()
|
||||
if (ChooseEnemy())
|
||||
{
|
||||
FoundEnemySound();
|
||||
|
||||
ClearCondition(COND_ENEMY_DEAD);
|
||||
return SelectSchedule();
|
||||
}
|
||||
@ -327,17 +302,20 @@ int CNPC_ShadowWalker::SelectCombatSchedule()
|
||||
|
||||
// If in a squad, only one or two shadow walkers can chase the player. This is configurable through Hammer.
|
||||
bool bCanChase = true;
|
||||
if (bEnemyCanSeeMe && m_bUseBothSquadSlots) {
|
||||
bCanChase = OccupyStrategySlotRange(SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2);
|
||||
if (m_bUseBothSquadSlots) {
|
||||
bCanChase = OccupyStrategySlotRange(SQUAD_SLOT_CHASE_1, SQUAD_SLOT_CHASE_2);
|
||||
}
|
||||
else if (bEnemyCanSeeMe){
|
||||
bCanChase = OccupyStrategySlot(SQUAD_SLOT_ATTACK1);
|
||||
else {
|
||||
bCanChase = OccupyStrategySlot(SQUAD_SLOT_CHASE_1);
|
||||
}
|
||||
|
||||
bCanChase = bCanChase || EnemyDistance(GetEnemy()) < 128;
|
||||
|
||||
// If I'm not allowed to chase this enemy of this enemy and he's looking at me, set up an ambush
|
||||
if (!bCanChase)
|
||||
{
|
||||
FearSound();
|
||||
SetState((NPC_STATE)NPC_STATE_AMBUSH);
|
||||
return SCHED_HIDE;
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ public:
|
||||
void Spawn(void);
|
||||
Class_T Classify(void);
|
||||
virtual int SelectFailSchedule(int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode);
|
||||
virtual int SelectSchedule();
|
||||
virtual int SelectIdleSchedule();
|
||||
virtual int SelectAlertSchedule();
|
||||
virtual int SelectCombatSchedule();
|
||||
|
Loading…
x
Reference in New Issue
Block a user