mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-04-20 16:32:30 +03:00
Merge branch 'base-custom-npc' of https://github.com/1upD/source-sdk-2013 into dev
This commit is contained in:
commit
6284c20d20
447
sp/src/game/server/mod/npc_base_custom.cpp
Normal file
447
sp/src/game/server/mod/npc_base_custom.cpp
Normal file
@ -0,0 +1,447 @@
|
||||
//=//=============================================================================//
|
||||
//
|
||||
// Purpose: A base class from which to extend new custom NPCs.
|
||||
// This class may seem redundant with CAI_BaseNPC and a lot of Valve's NPC classes.
|
||||
// However, the redundancy is necessary for compatibility with a variety of mods;
|
||||
// I want all new NPC content to be isolated from existing classes.
|
||||
//
|
||||
// Author: 1upD
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "npc_base_custom.h"
|
||||
#include "ai_hull.h"
|
||||
#include "soundent.h"
|
||||
#include "game.h"
|
||||
#include "npcevent.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "basehlcombatweapon_shared.h"
|
||||
#include "ai_squadslot.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Constants
|
||||
//---------------------------------------------------------
|
||||
// TODO: Replace these with fields so that other NPCs can override them
|
||||
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:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::Precache( void )
|
||||
{
|
||||
// If no model name is supplied, use the default citizen model
|
||||
if (!GetModelName())
|
||||
{
|
||||
SetModelName(MAKE_STRING("models/monster/subject.mdl")); // TODO replace this with citizen
|
||||
}
|
||||
|
||||
if (&m_iszWeaponModelName && m_iszWeaponModelName != MAKE_STRING("")) {
|
||||
PrecacheModel(STRING(m_iszWeaponModelName));
|
||||
}
|
||||
else {
|
||||
PrecacheModel("models/props_canal/mattpipe.mdl"); // Default weapon model
|
||||
}
|
||||
|
||||
PrecacheModel(STRING(GetModelName()));
|
||||
PrecacheNPCSoundScript(&m_iszFearSound, MAKE_STRING("NPC_BaseCustomr.Fear"));
|
||||
PrecacheNPCSoundScript(&m_iszIdleSound, MAKE_STRING("NPC_BaseCustom.Idle"));
|
||||
PrecacheNPCSoundScript(&m_iszAlertSound, MAKE_STRING("NPC_BaseCustom.Alert"));
|
||||
PrecacheNPCSoundScript(&m_iszPainSound, MAKE_STRING("NPC_BaseCustom.Pain"));
|
||||
PrecacheNPCSoundScript(&m_iszLostEnemySound, MAKE_STRING("NPC_BaseCustom.LostEnemy"));
|
||||
PrecacheNPCSoundScript(&m_iszFoundEnemySound, MAKE_STRING("NPC_BaseCustom.FoundEnemy"));
|
||||
PrecacheNPCSoundScript(&m_iszDeathSound, MAKE_STRING("NPC_BaseCustom.Death"));
|
||||
|
||||
m_bWanderToggle = false;
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
SetModel(STRING(GetModelName()));
|
||||
SetHullType(HULL_HUMAN);
|
||||
SetHullSizeNormal();
|
||||
|
||||
SetSolid( SOLID_BBOX );
|
||||
AddSolidFlags( FSOLID_NOT_STANDABLE );
|
||||
SetMoveType( MOVETYPE_STEP );
|
||||
SetBloodColor( BLOOD_COLOR_RED );
|
||||
|
||||
// If the health has not been set through Hammer, use a default health value of 75
|
||||
if (m_iHealth < 1)
|
||||
{
|
||||
m_iHealth = 75;
|
||||
}
|
||||
|
||||
m_flFieldOfView = 0.5;
|
||||
m_flNextSoundTime = gpGlobals->curtime;
|
||||
m_flNextFoundEnemySoundTime = gpGlobals->curtime;
|
||||
m_NPCState = NPC_STATE_NONE;
|
||||
m_flSpeedModifier = 1.0f;
|
||||
|
||||
CapabilitiesClear();
|
||||
|
||||
if (!HasSpawnFlags(SF_NPC_START_EFFICIENT))
|
||||
{
|
||||
CapabilitiesAdd(bits_CAP_ANIMATEDFACE | bits_CAP_TURN_HEAD); // The default model has no face animations, but a custom model might
|
||||
CapabilitiesAdd(bits_CAP_SQUAD);
|
||||
CapabilitiesAdd(bits_CAP_USE_WEAPONS | bits_CAP_AIM_GUN | bits_CAP_MOVE_SHOOT);
|
||||
CapabilitiesAdd(bits_CAP_WEAPON_MELEE_ATTACK1 || bits_CAP_WEAPON_MELEE_ATTACK2);
|
||||
CapabilitiesAdd(bits_CAP_DUCK);
|
||||
CapabilitiesAdd(bits_CAP_USE_SHOT_REGULATOR);
|
||||
|
||||
if (!m_bCannotOpenDoors) {
|
||||
CapabilitiesAdd(bits_CAP_DOORS_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
CapabilitiesAdd(bits_CAP_MOVE_GROUND);
|
||||
SetMoveType(MOVETYPE_STEP);
|
||||
|
||||
NPCInit();
|
||||
}
|
||||
|
||||
void CNPC_BaseCustomNPC::Activate()
|
||||
{
|
||||
BaseClass::Activate();
|
||||
FixupWeapon();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: If this NPC has some kind of custom weapon behavior,
|
||||
// set up the weapon after spawn.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::FixupWeapon()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Choose a schedule after schedule failed
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectFailSchedule(int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode)
|
||||
{
|
||||
switch (failedSchedule)
|
||||
{
|
||||
case SCHED_NEW_WEAPON:
|
||||
// If failed trying to pick up a weapon, try again in one second. This is because other AI code
|
||||
// has put this off for 10 seconds under the assumption that the citizen would be able to
|
||||
// pick up the weapon that they found.
|
||||
m_flNextWeaponSearchTime = gpGlobals->curtime + 1.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
return BaseClass::SelectFailSchedule(failedSchedule, failedTask, taskFailCode);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Select a schedule to retrieve better weapons if they are available.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectScheduleRetrieveItem()
|
||||
{
|
||||
if (m_bCanPickupWeapons && HasCondition(COND_BETTER_WEAPON_AVAILABLE))
|
||||
{
|
||||
CBaseHLCombatWeapon *pWeapon = dynamic_cast<CBaseHLCombatWeapon *>(Weapon_FindUsable(WEAPON_SEARCH_DELTA));
|
||||
if (pWeapon)
|
||||
{
|
||||
m_flNextWeaponSearchTime = gpGlobals->curtime + 10.0;
|
||||
// Now lock the weapon for several seconds while we go to pick it up.
|
||||
pWeapon->Lock(10.0, this);
|
||||
SetTarget(pWeapon);
|
||||
return SCHED_NEW_WEAPON;
|
||||
}
|
||||
}
|
||||
|
||||
return SCHED_NONE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Select a schedule to retrieve better weapons if they are available.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::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.
|
||||
// This is the most critical AI method.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::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
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectIdleSchedule()
|
||||
{
|
||||
int nSched = SelectFlinchSchedule();
|
||||
if (nSched != SCHED_NONE)
|
||||
return nSched;
|
||||
|
||||
if (HasCondition(COND_HEAR_DANGER) ||
|
||||
HasCondition(COND_HEAR_COMBAT) ||
|
||||
HasCondition(COND_HEAR_WORLD) ||
|
||||
HasCondition(COND_HEAR_BULLET_IMPACT) ||
|
||||
HasCondition(COND_HEAR_PLAYER))
|
||||
{
|
||||
// Investigate sound source
|
||||
return SCHED_ALERT_FACE_BESTSOUND;
|
||||
}
|
||||
|
||||
nSched = SelectScheduleRetrieveItem();
|
||||
if (nSched != SCHED_NONE)
|
||||
return nSched;
|
||||
|
||||
// no valid route! Wander instead
|
||||
if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) {
|
||||
return SCHED_IDLE_STAND;
|
||||
}
|
||||
|
||||
// valid route. Get moving
|
||||
return SCHED_IDLE_WALK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Alert schedule selection
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectAlertSchedule()
|
||||
{
|
||||
// Per default base NPC, check flinch schedule first
|
||||
int nSched = SelectFlinchSchedule();
|
||||
if (nSched != SCHED_NONE)
|
||||
return nSched;
|
||||
|
||||
// Scan around for new enemies
|
||||
if (HasCondition(COND_ENEMY_DEAD) && SelectWeightedSequence(ACT_VICTORY_DANCE) != ACTIVITY_NOT_AVAILABLE)
|
||||
return SCHED_ALERT_SCAN;
|
||||
|
||||
if (HasCondition(COND_HEAR_DANGER) ||
|
||||
HasCondition(COND_HEAR_PLAYER) ||
|
||||
HasCondition(COND_HEAR_WORLD) ||
|
||||
HasCondition(COND_HEAR_BULLET_IMPACT) ||
|
||||
HasCondition(COND_HEAR_COMBAT))
|
||||
{
|
||||
// Investigate sound source
|
||||
AlertSound();
|
||||
return SCHED_ALERT_FACE_BESTSOUND;
|
||||
}
|
||||
|
||||
nSched = SelectScheduleRetrieveItem();
|
||||
if (nSched != SCHED_NONE)
|
||||
return nSched;
|
||||
|
||||
// no valid route! Wander instead
|
||||
if (GetNavigator()->GetGoalType() == GOALTYPE_NONE) {
|
||||
return SCHED_ALERT_STAND;
|
||||
}
|
||||
|
||||
// valid route. Get moving
|
||||
return SCHED_ALERT_WALK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Combat schedule selection
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::SelectCombatSchedule()
|
||||
{
|
||||
return BaseClass::SelectSchedule(); // Let Base NPC handle it
|
||||
}
|
||||
|
||||
bool CNPC_BaseCustomNPC::HasRangedWeapon()
|
||||
{
|
||||
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
||||
|
||||
if (pWeapon)
|
||||
return !(FClassnameIs(pWeapon, "weapon_crowbar") || FClassnameIs(pWeapon, "weapon_stunstick"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override base class activiites
|
||||
//-----------------------------------------------------------------------------
|
||||
Activity CNPC_BaseCustomNPC::NPC_TranslateActivity(Activity activity)
|
||||
{
|
||||
switch (activity) {
|
||||
case ACT_RUN_AIM_SHOTGUN:
|
||||
return ACT_RUN_AIM_RIFLE;
|
||||
case ACT_WALK_AIM_SHOTGUN:
|
||||
return ACT_WALK_AIM_RIFLE;
|
||||
case ACT_IDLE_ANGRY_SHOTGUN:
|
||||
return ACT_IDLE_ANGRY_SMG1;
|
||||
case ACT_RANGE_ATTACK_SHOTGUN_LOW:
|
||||
return ACT_RANGE_ATTACK_SMG1_LOW;
|
||||
case ACT_IDLE_MELEE:
|
||||
case ACT_IDLE_ANGRY_MELEE: // If the NPC has a melee weapon but is in an idle state, don't raise the weapon
|
||||
if (m_NPCState == NPC_STATE_IDLE)
|
||||
return ACT_IDLE_SUITCASE;
|
||||
default:
|
||||
return BaseClass::NPC_TranslateActivity(activity);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Override base class schedules
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_BaseCustomNPC::TranslateSchedule(int scheduleType)
|
||||
{
|
||||
return BaseClass::TranslateSchedule(scheduleType);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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_BaseCustomNPC::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
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::PlaySound(string_t soundname, bool required /*= false */)
|
||||
{
|
||||
// TODO: Check if silent
|
||||
if (required || gpGlobals->curtime > m_flNextSoundTime)
|
||||
{
|
||||
m_flNextSoundTime = gpGlobals->curtime + random->RandomFloat(MIN_TIME_NEXT_SOUND, MAX_TIME_NEXT_SOUND);
|
||||
//CPASAttenuationFilter filter2(this, STRING(soundname));
|
||||
EmitSound(STRING(soundname));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Assign a default soundscript if none is provided, then precache
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::PrecacheNPCSoundScript(string_t * SoundName, string_t defaultSoundName)
|
||||
{
|
||||
if (!SoundName) {
|
||||
*SoundName = defaultSoundName;
|
||||
}
|
||||
PrecacheScriptSound(STRING(*SoundName));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get movement speed, multipled by modifier
|
||||
//-----------------------------------------------------------------------------
|
||||
float CNPC_BaseCustomNPC::GetSequenceGroundSpeed(CStudioHdr *pStudioHdr, int iSequence)
|
||||
{
|
||||
float t = SequenceDuration(pStudioHdr, iSequence);
|
||||
|
||||
if (t > 0)
|
||||
{
|
||||
return (GetSequenceMoveDist(pStudioHdr, iSequence) * m_flSpeedModifier / t);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hammer input to change the speed of the NPC
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::InputSetSpeedModifier(inputdata_t &inputdata)
|
||||
{
|
||||
this->m_flSpeedModifier = inputdata.value.Float();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hammer input to enable opening doors
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::InputEnableOpenDoors(inputdata_t &inputdata)
|
||||
{
|
||||
m_bCannotOpenDoors = false;
|
||||
if (!HasSpawnFlags(SF_NPC_START_EFFICIENT))
|
||||
{
|
||||
CapabilitiesAdd(bits_CAP_DOORS_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hammer input to enable opening doors
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::InputDisableOpenDoors(inputdata_t &inputdata)
|
||||
{
|
||||
m_bCannotOpenDoors = true;
|
||||
if (!HasSpawnFlags(SF_NPC_START_EFFICIENT))
|
||||
{
|
||||
CapabilitiesRemove(bits_CAP_DOORS_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hammer input to enable weapon pickup behavior
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::InputEnablePickupWeapons(inputdata_t &inputdata)
|
||||
{
|
||||
m_bCanPickupWeapons = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hammer input to enable weapon pickup behavior
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_BaseCustomNPC::InputDisablePickupWeapons(inputdata_t &inputdata)
|
||||
{
|
||||
m_bCanPickupWeapons = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
Class_T CNPC_BaseCustomNPC::Classify( void )
|
||||
{
|
||||
return CLASS_NONE;
|
||||
}
|
177
sp/src/game/server/mod/npc_base_custom.h
Normal file
177
sp/src/game/server/mod/npc_base_custom.h
Normal file
@ -0,0 +1,177 @@
|
||||
//=//=============================================================================//
|
||||
//
|
||||
// Purpose: A base class from which to extend new custom NPCs.
|
||||
// This class may seem redundant with CAI_BaseNPC and a lot of Valve's NPC classes.
|
||||
// However, the redundancy is necessary for compatibility with a variety of mods;
|
||||
// I want all new NPC content to be isolated from existing classes.
|
||||
//
|
||||
// Author: 1upD
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "ai_default.h"
|
||||
#include "ai_task.h"
|
||||
#include "ai_schedule.h"
|
||||
#include "entitylist.h"
|
||||
#include "activitylist.h"
|
||||
#include "ai_basenpc.h"
|
||||
#include "ai_blended_movement.h"
|
||||
#include "ai_behavior_actbusy.h"
|
||||
|
||||
//=========================================================
|
||||
// schedules
|
||||
//=========================================================
|
||||
enum
|
||||
{
|
||||
SCHED_MELEE_ATTACK_NOINTERRUPT = LAST_SHARED_SCHEDULE,
|
||||
SCHED_HIDE,
|
||||
|
||||
LAST_BASE_CUSTOM_SCHED
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
typedef CAI_BlendingHost< CAI_BehaviorHost<CAI_BaseNPC> > CAI_CustomNPCBase;
|
||||
|
||||
class CNPC_BaseCustomNPC : public CAI_CustomNPCBase
|
||||
{
|
||||
DECLARE_CLASS(CNPC_BaseCustomNPC, CAI_CustomNPCBase);
|
||||
|
||||
public:
|
||||
void Precache(void);
|
||||
void Spawn(void);
|
||||
Class_T Classify(void);
|
||||
virtual int SelectFailSchedule(int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode);
|
||||
virtual int SelectScheduleRetrieveItem();
|
||||
virtual int SelectScheduleWander();
|
||||
virtual int SelectSchedule();
|
||||
virtual int SelectIdleSchedule();
|
||||
virtual int SelectAlertSchedule();
|
||||
virtual int SelectCombatSchedule();
|
||||
virtual float GetSequenceGroundSpeed(CStudioHdr *pStudioHdr, int iSequence);
|
||||
virtual Activity NPC_TranslateActivity(Activity eNewActivity);
|
||||
virtual int TranslateSchedule(int scheduleType);
|
||||
|
||||
// Sounds
|
||||
virtual void PlaySound(string_t soundname, bool optional);
|
||||
virtual void DeathSound(const CTakeDamageInfo &info) { PlaySound(m_iszDeathSound, true); }
|
||||
virtual void AlertSound(void) { PlaySound(m_iszAlertSound, false); };
|
||||
virtual void IdleSound(void) { PlaySound(m_iszIdleSound, false); };
|
||||
virtual void PainSound(const CTakeDamageInfo &info) { PlaySound(m_iszPainSound, true); };
|
||||
virtual void FearSound(void) { PlaySound(m_iszFearSound, false); };
|
||||
virtual void LostEnemySound(void) { PlaySound(m_iszLostEnemySound, false); };
|
||||
virtual void FoundEnemySound(void);
|
||||
|
||||
void Activate();
|
||||
virtual void FixupWeapon();
|
||||
|
||||
// Inputs
|
||||
virtual void InputSetSpeedModifier(inputdata_t &inputdata);
|
||||
virtual void InputEnableOpenDoors(inputdata_t &inputdata);
|
||||
virtual void InputDisableOpenDoors(inputdata_t &inputdata);
|
||||
virtual void InputEnablePickupWeapons(inputdata_t &inputdata);
|
||||
virtual void InputDisablePickupWeapons(inputdata_t &inputdata);
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
string_t m_iszWeaponModelName; // Path/filename of model to override weapon model.
|
||||
|
||||
string_t m_iszFearSound; // Path/filename of WAV file to play.
|
||||
string_t m_iszDeathSound; // Path/filename of WAV file to play.
|
||||
string_t m_iszIdleSound; // Path/filename of WAV file to play.
|
||||
string_t m_iszPainSound; // Path/filename of WAV file to play.
|
||||
string_t m_iszAlertSound; // Path/filename of WAV file to play.
|
||||
string_t m_iszLostEnemySound; // Path/filename of WAV file to play.
|
||||
string_t m_iszFoundEnemySound; // Path/filename of WAV file to play.
|
||||
|
||||
DEFINE_CUSTOM_AI;
|
||||
|
||||
protected:
|
||||
bool HasRangedWeapon();
|
||||
void PrecacheNPCSoundScript(string_t* SoundName, string_t defaultSoundName);
|
||||
|
||||
|
||||
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.
|
||||
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_flNextFoundEnemySoundTime; // Next time at which this NPC is allowed to play an NPC sound
|
||||
float m_flSpeedModifier; // Modifier to apply to move distance
|
||||
};
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS(npc_base_custom, CNPC_BaseCustomNPC);
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Save/Restore
|
||||
//---------------------------------------------------------
|
||||
BEGIN_DATADESC(CNPC_BaseCustomNPC)
|
||||
DEFINE_KEYFIELD(m_iszWeaponModelName, FIELD_STRING, "WeaponModel"),
|
||||
DEFINE_KEYFIELD(m_iHealth, FIELD_INTEGER, "Health"),
|
||||
DEFINE_KEYFIELD(m_iszFearSound, FIELD_SOUNDNAME, "FearSound"),
|
||||
DEFINE_KEYFIELD(m_iszDeathSound, FIELD_SOUNDNAME, "DeathSound"),
|
||||
DEFINE_KEYFIELD(m_iszIdleSound, FIELD_SOUNDNAME, "IdleSound"),
|
||||
DEFINE_KEYFIELD(m_iszPainSound, FIELD_SOUNDNAME, "PainSound"),
|
||||
DEFINE_KEYFIELD(m_iszAlertSound, FIELD_SOUNDNAME, "AlertSound"),
|
||||
DEFINE_KEYFIELD(m_iszLostEnemySound, FIELD_SOUNDNAME, "LostEnemySound"),
|
||||
DEFINE_KEYFIELD(m_iszFoundEnemySound, FIELD_SOUNDNAME, "FoundEnemySound"),
|
||||
DEFINE_KEYFIELD(m_bUseBothSquadSlots, FIELD_BOOLEAN, "UseBothSquadSlots"),
|
||||
DEFINE_KEYFIELD(m_bCannotOpenDoors, FIELD_BOOLEAN, "CannotOpenDoors"),
|
||||
DEFINE_KEYFIELD(m_bCanPickupWeapons, FIELD_BOOLEAN, "CanPickupWeapons"),
|
||||
|
||||
DEFINE_FIELD(m_bWanderToggle, FIELD_BOOLEAN),
|
||||
DEFINE_FIELD(m_flNextSoundTime, FIELD_TIME),
|
||||
DEFINE_FIELD(m_flNextFoundEnemySoundTime, FIELD_TIME),
|
||||
DEFINE_FIELD(m_flSpeedModifier, FIELD_TIME),
|
||||
|
||||
DEFINE_INPUTFUNC(FIELD_FLOAT, "SetSpeedModifier", InputSetSpeedModifier),
|
||||
DEFINE_INPUTFUNC(FIELD_VOID, "EnableOpenDoors", InputEnableOpenDoors),
|
||||
DEFINE_INPUTFUNC(FIELD_VOID, "DisableOpenDoors", InputDisableOpenDoors),
|
||||
DEFINE_INPUTFUNC(FIELD_VOID, "EnablePickupWeapons", InputEnablePickupWeapons),
|
||||
DEFINE_INPUTFUNC(FIELD_VOID, "DisablePickupWeapons", InputDisablePickupWeapons)
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
AI_BEGIN_CUSTOM_NPC(npc_base_custom, CNPC_BaseCustomNPC)
|
||||
//=========================================================
|
||||
// > Melee_Attack_NoInterrupt
|
||||
//=========================================================
|
||||
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
|
||||
//=========================================================
|
||||
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"
|
||||
);
|
||||
AI_END_CUSTOM_NPC()
|
||||
|
@ -52,12 +52,13 @@ $Project "Server (Episodic)"
|
||||
{
|
||||
$Folder "Mod"
|
||||
{
|
||||
$File "mod\npc_lost_soul.cpp"
|
||||
$File "mod\npc_shadow_walker.h"
|
||||
$File "mod\npc_shadow_walker.cpp"
|
||||
$File "mod\weapon_custom_melee.h"
|
||||
}
|
||||
$File "$SRCDIR\game\shared\episodic\achievements_ep1.cpp"
|
||||
$File "mod\npc_base_custom.h"
|
||||
$File "mod\npc_base_custom.cpp"
|
||||
$File "mod\npc_lost_soul.cpp"
|
||||
$File "mod\npc_shadow_walker.h"
|
||||
$File "mod\npc_shadow_walker.cpp"
|
||||
$File "mod\weapon_custom_melee.h"
|
||||
} $File "$SRCDIR\game\shared\episodic\achievements_ep1.cpp"
|
||||
$File "$SRCDIR\game\shared\episodic\achievements_ep2.cpp"
|
||||
$File "$SRCDIR\game\shared\episodic\achievements_epx.cpp"
|
||||
$File "hl2\ai_allymanager.cpp"
|
||||
|
Loading…
x
Reference in New Issue
Block a user