Merged changes made in my local MapLabs repo with changes made to my own repo

This commit is contained in:
1upD 2018-10-22 18:21:41 -04:00
parent fdffc94a13
commit ef5a5ef39f
2 changed files with 171 additions and 30 deletions

View File

@ -50,9 +50,17 @@
0 : "Can Open Doors" 0 : "Can Open Doors"
1 : "Cannot Open Doors" 1 : "Cannot Open Doors"
] ]
CanPickupWeapons(choices) : "Can Pick Up Guns?" : 0 : "Is this NPC able to pick up guns? You can change this after spawning with EnablePickupWeapons and DisablePickupWeapons." =
[
0 : "Cannot Pick Up Guns"
1 : "Can Pick Up Guns"
]
input SetSpeedModifier(float) : "Set a float value to multiple distance traveled by." input SetSpeedModifier(float) : "Set a float value to multiple distance traveled by."
input EnableOpenDoors(void) : "Allow this NPC to open doors. (Warning: Doesn't always seem to update pathfinding / AI)" input EnableOpenDoors(void) : "Allow this NPC to open doors. (Warning: Doesn't always seem to update pathfinding / AI)"
input DisableOpenDoors(void) : "Prevent this NPC from opening doors." input DisableOpenDoors(void) : "Prevent this NPC from opening doors."
input EnablePickupWeapons(void) : "Allow this NPC to pick up any weapon off of the ground."
input DisablePickupWeapons(void) : "Prevent this NPC from picking up weapons."
] ]
@NPCClass base(npc_manhack) studio("models/skeleton/skeleton_torso3.mdl") = npc_lost_soul : "Lost Soul" @NPCClass base(npc_manhack) studio("models/skeleton/skeleton_torso3.mdl") = npc_lost_soul : "Lost Soul"

View File

@ -29,6 +29,15 @@
// memdbgon must be the last include file in a .cpp file!!! // memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h" #include "tier0/memdbgon.h"
//=========================================================
// schedules
//=========================================================
enum
{
SCHED_MELEE_ATTACK_NOINTERRUPT,
SCHED_HIDE
};
//========================================================= //=========================================================
//========================================================= //=========================================================
class CNPC_ShadowWalker : public CAI_BaseNPC class CNPC_ShadowWalker : public CAI_BaseNPC
@ -41,13 +50,15 @@ public:
Class_T Classify( void ); Class_T Classify( void );
virtual int SelectFailSchedule(int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode); virtual int SelectFailSchedule(int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode);
virtual int SelectScheduleRetrieveItem(); virtual int SelectScheduleRetrieveItem();
virtual int SelectScheduleWander();
virtual int SelectSchedule(); virtual int SelectSchedule();
virtual int SelectIdleSchedule(); virtual int SelectIdleSchedule();
virtual int SelectAlertSchedule(); virtual int SelectAlertSchedule();
virtual int SelectCombatSchedule(); virtual int SelectCombatSchedule();
virtual bool CanPickkUpWeapons() { return true; } virtual bool CanPickkUpWeapons() { return m_bCanPickupWeapons; }
virtual float GetSequenceGroundSpeed(CStudioHdr *pStudioHdr, int iSequence); virtual float GetSequenceGroundSpeed(CStudioHdr *pStudioHdr, int iSequence);
Activity NPC_TranslateActivity(Activity eNewActivity); Activity NPC_TranslateActivity(Activity eNewActivity);
virtual int TranslateSchedule(int scheduleType);
// Sounds // Sounds
virtual void PlaySound(string_t soundname, bool optional); virtual void PlaySound(string_t soundname, bool optional);
@ -57,7 +68,7 @@ public:
virtual void PainSound(const CTakeDamageInfo &info) { PlaySound(m_iszPainSound, true); }; virtual void PainSound(const CTakeDamageInfo &info) { PlaySound(m_iszPainSound, true); };
virtual void FearSound(void) { PlaySound(m_iszFearSound, false); }; virtual void FearSound(void) { PlaySound(m_iszFearSound, false); };
virtual void LostEnemySound(void) { PlaySound(m_iszLostEnemySound, false); }; virtual void LostEnemySound(void) { PlaySound(m_iszLostEnemySound, false); };
virtual void FoundEnemySound(void) { PlaySound(m_iszFoundEnemySound, false); }; virtual void FoundEnemySound(void);
void Activate(); void Activate();
void FixupWeapon(); void FixupWeapon();
@ -66,6 +77,8 @@ public:
virtual void InputSetSpeedModifier(inputdata_t &inputdata); virtual void InputSetSpeedModifier(inputdata_t &inputdata);
virtual void InputEnableOpenDoors(inputdata_t &inputdata); virtual void InputEnableOpenDoors(inputdata_t &inputdata);
virtual void InputDisableOpenDoors(inputdata_t &inputdata); virtual void InputDisableOpenDoors(inputdata_t &inputdata);
virtual void InputEnablePickupWeapons(inputdata_t &inputdata);
virtual void InputDisablePickupWeapons(inputdata_t &inputdata);
DECLARE_DATADESC(); DECLARE_DATADESC();
@ -88,8 +101,10 @@ private:
bool m_bUseBothSquadSlots; // If true use two squad slots, if false use one squad slot 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_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.
bool m_bWanderToggle; // Boolean to toggle wandering / standing every think cycle bool m_bWanderToggle; // Boolean to toggle wandering / standing every think cycle
float m_flNextSoundTime; // Next time at which this NPC is allowed to play an NPC sound float m_flNextSoundTime; // Next time at which this NPC is allowed to play an NPC sound
float m_flNextFoundEnemySoundTime; // Next time at which this NPC is allowed to play an NPC sound
float m_flSpeedModifier; // Modifier to apply to move distance float m_flSpeedModifier; // Modifier to apply to move distance
}; };
@ -113,16 +128,68 @@ BEGIN_DATADESC(CNPC_ShadowWalker)
DEFINE_KEYFIELD(m_iszFoundEnemySound, FIELD_SOUNDNAME, "FoundEnemySound"), DEFINE_KEYFIELD(m_iszFoundEnemySound, FIELD_SOUNDNAME, "FoundEnemySound"),
DEFINE_KEYFIELD(m_bUseBothSquadSlots, FIELD_BOOLEAN, "UseBothSquadSlots"), DEFINE_KEYFIELD(m_bUseBothSquadSlots, FIELD_BOOLEAN, "UseBothSquadSlots"),
DEFINE_KEYFIELD(m_bCannotOpenDoors, FIELD_BOOLEAN, "CannotOpenDoors"), DEFINE_KEYFIELD(m_bCannotOpenDoors, FIELD_BOOLEAN, "CannotOpenDoors"),
DEFINE_KEYFIELD(m_bCanPickupWeapons, FIELD_BOOLEAN, "CanPickupWeapons"),
DEFINE_FIELD(m_bWanderToggle, FIELD_BOOLEAN), DEFINE_FIELD(m_bWanderToggle, FIELD_BOOLEAN),
DEFINE_FIELD(m_flNextSoundTime, FIELD_TIME), DEFINE_FIELD(m_flNextSoundTime, FIELD_TIME),
DEFINE_FIELD(m_flNextFoundEnemySoundTime, FIELD_TIME),
DEFINE_FIELD(m_flSpeedModifier, FIELD_TIME), DEFINE_FIELD(m_flSpeedModifier, FIELD_TIME),
DEFINE_INPUTFUNC(FIELD_FLOAT, "SetSpeedModifier", InputSetSpeedModifier), DEFINE_INPUTFUNC(FIELD_FLOAT, "SetSpeedModifier", InputSetSpeedModifier),
DEFINE_INPUTFUNC(FIELD_VOID, "EnableOpenDoors", InputEnableOpenDoors), DEFINE_INPUTFUNC(FIELD_VOID, "EnableOpenDoors", InputEnableOpenDoors),
DEFINE_INPUTFUNC(FIELD_VOID, "DisableOpenDoors", InputDisableOpenDoors) DEFINE_INPUTFUNC(FIELD_VOID, "DisableOpenDoors", InputDisableOpenDoors),
DEFINE_INPUTFUNC(FIELD_VOID, "EnablePickupWeapons", InputEnablePickupWeapons),
DEFINE_INPUTFUNC(FIELD_VOID, "DisablePickupWeapons", InputDisablePickupWeapons)
END_DATADESC() END_DATADESC()
//=========================================================
// > Melee_Attack_NoInterrupt
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_MELEE_ATTACK_NOINTERRUPT,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_FACE_ENEMY 0"
" TASK_ANNOUNCE_ATTACK 1" // 1 = primary attack
" TASK_MELEE_ATTACK1 0"
""
" Interrupts"
" COND_ENEMY_DEAD"
" COND_ENEMY_OCCLUDED"
);
//=========================================================
// SCHED_HIDE
//=========================================================
AI_DEFINE_SCHEDULE
(
SCHED_HIDE,
" Tasks"
" TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_COMBAT_FACE"
" TASK_STOP_MOVING 0"
" TASK_FIND_COVER_FROM_ENEMY 0"
" TASK_RUN_PATH 0"
" TASK_WAIT_FOR_MOVEMENT 0"
" TASK_REMEMBER MEMORY:INCOVER"
" TASK_FACE_ENEMY 0"
""
" Interrupts"
" COND_HEAR_DANGER"
" COND_NEW_ENEMY"
" COND_ENEMY_DEAD"
);
//---------------------------------------------------------
// Constants
//---------------------------------------------------------
const float MIN_TIME_NEXT_SOUND = 0.5f;
const float MAX_TIME_NEXT_SOUND = 1.0f;
const float MIN_TIME_NEXT_FOUNDENEMY_SOUND = 2.0f;
const float MAX_TIME_NEXT_FOUNDENEMY_SOUND = 5.0f;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Initialize the custom schedules // Purpose: Initialize the custom schedules
// Input : // Input :
@ -206,6 +273,7 @@ void CNPC_ShadowWalker::Spawn( void )
m_flFieldOfView = 0.5; m_flFieldOfView = 0.5;
m_flNextSoundTime = gpGlobals->curtime; m_flNextSoundTime = gpGlobals->curtime;
m_flNextFoundEnemySoundTime = gpGlobals->curtime;
m_NPCState = NPC_STATE_NONE; m_NPCState = NPC_STATE_NONE;
m_flSpeedModifier = 1.0f; m_flSpeedModifier = 1.0f;
@ -256,9 +324,6 @@ void CNPC_ShadowWalker::FixupWeapon()
} }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CNPC_ShadowWalker::Activate() void CNPC_ShadowWalker::Activate()
{ {
BaseClass::Activate(); BaseClass::Activate();
@ -314,6 +379,20 @@ int CNPC_ShadowWalker::SelectScheduleRetrieveItem()
return SCHED_NONE; return SCHED_NONE;
} }
//-----------------------------------------------------------------------------
// Purpose: Select a schedule to retrieve better weapons if they are available.
//-----------------------------------------------------------------------------
int CNPC_ShadowWalker::SelectScheduleWander()
{
m_bWanderToggle = !m_bWanderToggle;
if (m_bWanderToggle) {
return SCHED_IDLE_WANDER;
}
else {
return SCHED_NONE;
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Select a schedule to execute based on conditions. // Purpose: Select a schedule to execute based on conditions.
// This is the most critical AI method. // This is the most critical AI method.
@ -357,7 +436,7 @@ int CNPC_ShadowWalker::SelectIdleSchedule()
return SCHED_INVESTIGATE_SOUND; return SCHED_INVESTIGATE_SOUND;
} }
if (CanPickkUpWeapons() && HasCondition(COND_BETTER_WEAPON_AVAILABLE)) { if (CanPickkUpWeapons()) {
nSched = SelectScheduleRetrieveItem(); nSched = SelectScheduleRetrieveItem();
if (nSched != SCHED_NONE) if (nSched != SCHED_NONE)
return nSched; return nSched;
@ -365,14 +444,10 @@ int CNPC_ShadowWalker::SelectIdleSchedule()
// no valid route! Wander instead // no valid route! Wander instead
if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) { if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) {
m_bWanderToggle = !m_bWanderToggle; nSched = SelectScheduleWander();
if (m_bWanderToggle) { if (nSched == SCHED_NONE)
return SCHED_IDLE_WANDER;
}
else {
return SCHED_IDLE_STAND; return SCHED_IDLE_STAND;
} }
}
// valid route. Get moving // valid route. Get moving
return SCHED_IDLE_WALK; return SCHED_IDLE_WALK;
@ -403,7 +478,7 @@ int CNPC_ShadowWalker::SelectAlertSchedule()
return SCHED_INVESTIGATE_SOUND; return SCHED_INVESTIGATE_SOUND;
} }
if (CanPickkUpWeapons() && HasCondition(COND_BETTER_WEAPON_AVAILABLE)) { if (CanPickkUpWeapons()) {
nSched = SelectScheduleRetrieveItem(); nSched = SelectScheduleRetrieveItem();
if (nSched != SCHED_NONE) if (nSched != SCHED_NONE)
return nSched; return nSched;
@ -411,13 +486,9 @@ int CNPC_ShadowWalker::SelectAlertSchedule()
// no valid route! Wander instead // no valid route! Wander instead
if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) { if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) {
m_bWanderToggle = !m_bWanderToggle; nSched = SelectScheduleWander();
if (m_bWanderToggle) { if (nSched == SCHED_NONE)
return SCHED_IDLE_WANDER; return SCHED_IDLE_STAND;
}
else {
return SCHED_ALERT_STAND;
}
} }
// valid route. Get moving // valid route. Get moving
@ -443,6 +514,7 @@ int CNPC_ShadowWalker::SelectCombatSchedule()
if (ChooseEnemy()) if (ChooseEnemy())
{ {
FoundEnemySound(); FoundEnemySound();
ClearCondition(COND_ENEMY_DEAD); ClearCondition(COND_ENEMY_DEAD);
return SelectSchedule(); return SelectSchedule();
} }
@ -451,21 +523,32 @@ int CNPC_ShadowWalker::SelectCombatSchedule()
return SelectSchedule(); return SelectSchedule();
} }
// Can any enemies see me?
bool bEnemyCanSeeMe = HasCondition(COND_SEE_ENEMY) && HasCondition(COND_ENEMY_FACING_ME) && HasCondition(COND_HAVE_ENEMY_LOS);
// If I'm scared of this enemy and he's looking at me, run away
if ((IRelationType(GetEnemy()) == D_FR) && bEnemyCanSeeMe)
{
FearSound();
return SCHED_RUN_FROM_ENEMY;
}
// If in a squad, only one or two shadow walkers can chase the player. This is configurable through Hammer. // If in a squad, only one or two shadow walkers can chase the player. This is configurable through Hammer.
bool bCanChase = false; bool bCanChase = true;
if (m_bUseBothSquadSlots) { if (bEnemyCanSeeMe && m_bUseBothSquadSlots) {
bCanChase = OccupyStrategySlotRange(SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2); bCanChase = OccupyStrategySlotRange(SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2);
} }
else { else if (bEnemyCanSeeMe){
bCanChase = OccupyStrategySlot(SQUAD_SLOT_ATTACK1); bCanChase = OccupyStrategySlot(SQUAD_SLOT_ATTACK1);
} }
// If I'm scared of this enemy and he's looking at me, run away // If I'm not allowed to chase this enemy of this enemy and he's looking at me, set up an ambush
if ((IRelationType(GetEnemy()) == D_FR || !bCanChase) && (HasCondition(COND_SEE_ENEMY) && HasCondition(COND_ENEMY_FACING_ME) && HasCondition(COND_HAVE_ENEMY_LOS))) if (!bCanChase)
{ {
// TODO: Check if silent
FearSound(); FearSound();
return SCHED_RUN_FROM_ENEMY; return SCHED_HIDE;
} }
// Reloading conditions are necessary just in case for some reason somebody gives the Shadow Walker a gun // Reloading conditions are necessary just in case for some reason somebody gives the Shadow Walker a gun
@ -537,12 +620,30 @@ bool CNPC_ShadowWalker::HasRangedWeapon()
return false; return false;
} }
//-----------------------------------------------------------------------------
// Purpose: Override base class schedules
//-----------------------------------------------------------------------------
int CNPC_ShadowWalker::TranslateSchedule(int scheduleType)
{
switch (scheduleType)
{
case SCHED_MELEE_ATTACK1:
return SCHED_MELEE_ATTACK_NOINTERRUPT;
case SCHED_IDLE_WANDER: // We want idle wandering to be interruptible - patrol walk is a better schedule
return SCHED_PATROL_WALK;
}
return BaseClass::TranslateSchedule(scheduleType);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Override base class activiites // Purpose: Override base class activiites
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
Activity CNPC_ShadowWalker::NPC_TranslateActivity(Activity activity) Activity CNPC_ShadowWalker::NPC_TranslateActivity(Activity activity)
{ {
switch (activity) { switch (activity) {
case ACT_IDLE_MELEE:
return ACT_IDLE; // If the walker has a melee weapon but is in an idle state, don't raise the weapon
case ACT_RUN_AIM_SHOTGUN: case ACT_RUN_AIM_SHOTGUN:
return ACT_RUN_AIM_RIFLE; return ACT_RUN_AIM_RIFLE;
case ACT_WALK_AIM_SHOTGUN: case ACT_WALK_AIM_SHOTGUN:
@ -556,14 +657,30 @@ Activity CNPC_ShadowWalker::NPC_TranslateActivity(Activity activity)
} }
} }
//-----------------------------------------------------------------------------
// Purpose: Play sound when an enemy is spotted. This sound has a separate
// timer from other sounds to prevent looping if the NPC gets caught
// in a 'found enemy' condition.
//-----------------------------------------------------------------------------
void CNPC_ShadowWalker::FoundEnemySound(void)
{
if (gpGlobals->curtime > m_flNextFoundEnemySoundTime)
{
m_flNextFoundEnemySoundTime = gpGlobals->curtime + random->RandomFloat(MIN_TIME_NEXT_FOUNDENEMY_SOUND, MAX_TIME_NEXT_FOUNDENEMY_SOUND);
PlaySound(m_iszFoundEnemySound, true);
}
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Play NPC soundscript // Purpose: Play NPC soundscript
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void CNPC_ShadowWalker::PlaySound(string_t soundname, bool required /*= false */) void CNPC_ShadowWalker::PlaySound(string_t soundname, bool required /*= false */)
{ {
// TODO: Check if silent
if (required || gpGlobals->curtime > m_flNextSoundTime) if (required || gpGlobals->curtime > m_flNextSoundTime)
{ {
m_flNextSoundTime = gpGlobals->curtime + random->RandomFloat(0.5, 1.0); m_flNextSoundTime = gpGlobals->curtime + random->RandomFloat(MIN_TIME_NEXT_SOUND, MAX_TIME_NEXT_SOUND);
//CPASAttenuationFilter filter2(this, STRING(soundname)); //CPASAttenuationFilter filter2(this, STRING(soundname));
EmitSound(STRING(soundname)); EmitSound(STRING(soundname));
} }
@ -629,6 +746,22 @@ void CNPC_ShadowWalker::InputDisableOpenDoors(inputdata_t &inputdata)
} }
} }
//-----------------------------------------------------------------------------
// Purpose: Hammer input to enable weapon pickup behavior
//-----------------------------------------------------------------------------
void CNPC_ShadowWalker::InputEnablePickupWeapons(inputdata_t &inputdata)
{
m_bCanPickupWeapons = true;
}
//-----------------------------------------------------------------------------
// Purpose: Hammer input to enable weapon pickup behavior
//-----------------------------------------------------------------------------
void CNPC_ShadowWalker::InputDisablePickupWeapons(inputdata_t &inputdata)
{
m_bCanPickupWeapons = false;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: // Purpose:
// //