434 lines
14 KiB
C++
434 lines
14 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#ifndef NPC_ANTLION_H
|
|
#define NPC_ANTLION_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "ai_behavior_assault.h"
|
|
#include "ai_behavior_follow.h"
|
|
#include "ai_blended_movement.h"
|
|
#include "soundent.h"
|
|
|
|
class CAntlionTemplateMaker;
|
|
|
|
#define ANTLION_FOLLOW_DISTANCE 350
|
|
#define ANTLION_FOLLOW_DISTANCE_SQR \
|
|
(ANTLION_FOLLOW_DISTANCE * ANTLION_FOLLOW_DISTANCE)
|
|
#define ANTLION_SKIN_COUNT 4
|
|
|
|
class CNPC_Antlion;
|
|
|
|
// Antlion follow behavior
|
|
class CAI_AntlionFollowBehavior : public CAI_FollowBehavior {
|
|
typedef CAI_FollowBehavior BaseClass;
|
|
|
|
public:
|
|
CAI_AntlionFollowBehavior() : BaseClass(AIF_ANTLION) {}
|
|
|
|
bool FarFromFollowTarget(void) {
|
|
return (
|
|
GetFollowTarget() &&
|
|
(GetAbsOrigin() - GetFollowTarget()->GetAbsOrigin()).LengthSqr() >
|
|
ANTLION_FOLLOW_DISTANCE_SQR);
|
|
}
|
|
|
|
bool ShouldFollow(void) {
|
|
if (GetFollowTarget() == NULL) return false;
|
|
|
|
if (GetEnemy() != NULL) return false;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Antlion class
|
|
//
|
|
|
|
enum AntlionMoveState_e {
|
|
ANTLION_MOVE_FREE,
|
|
ANTLION_MOVE_FOLLOW,
|
|
ANTLION_MOVE_FIGHT_TO_GOAL,
|
|
};
|
|
|
|
#define SF_ANTLION_BURROW_ON_ELUDED (1 << 16)
|
|
#define SF_ANTLION_USE_GROUNDCHECKS (1 << 17)
|
|
#define SF_ANTLION_WORKER (1 << 18) // Use the "worker" model
|
|
|
|
typedef CAI_BlendingHost<CAI_BehaviorHost<CAI_BlendedNPC> > CAI_BaseAntlionBase;
|
|
|
|
class CNPC_Antlion : public CAI_BaseAntlionBase {
|
|
public:
|
|
DECLARE_CLASS(CNPC_Antlion, CAI_BaseAntlionBase);
|
|
|
|
CNPC_Antlion(void);
|
|
|
|
virtual float InnateRange1MinRange(void) { return 50 * 12; }
|
|
virtual float InnateRange1MaxRange(void) { return 250 * 12; }
|
|
|
|
bool IsWorker(void) const {
|
|
return HasSpawnFlags(SF_ANTLION_WORKER);
|
|
} // NOTE: IsAntlionWorker function must agree!
|
|
|
|
float GetIdealAccel(void) const;
|
|
float MaxYawSpeed(void);
|
|
bool FInViewCone(CBaseEntity *pEntity);
|
|
bool FInViewCone(const Vector &vecSpot);
|
|
|
|
void Activate(void);
|
|
void HandleAnimEvent(animevent_t *pEvent);
|
|
void StartTask(const Task_t *pTask);
|
|
void RunTask(const Task_t *pTask);
|
|
void IdleSound(void);
|
|
void PainSound(const CTakeDamageInfo &info);
|
|
void Precache(void);
|
|
void Spawn(void);
|
|
int OnTakeDamage_Alive(const CTakeDamageInfo &info);
|
|
void TraceAttack(const CTakeDamageInfo &info, const Vector &vecDir,
|
|
trace_t *ptr, CDmgAccumulator *pAccumulator);
|
|
void BuildScheduleTestBits(void);
|
|
void GatherConditions(void);
|
|
void PrescheduleThink(void);
|
|
void ZapThink(void);
|
|
void BurrowUse(CBaseEntity *pActivator, CBaseEntity *pCaller,
|
|
USE_TYPE useType, float value);
|
|
bool CreateVPhysics();
|
|
|
|
bool IsJumpLegal(const Vector &startPos, const Vector &apex,
|
|
const Vector &endPos) const;
|
|
bool HandleInteraction(int interactionType, void *data,
|
|
CBaseCombatCharacter *sender = NULL);
|
|
bool QuerySeeEntity(CBaseEntity *pEntity,
|
|
bool bOnlyHateOrFearIfNPC = false);
|
|
bool ShouldPlayIdleSound(void);
|
|
bool OverrideMoveFacing(const AILocalMoveGoal_t &move, float flInterval);
|
|
bool IsValidEnemy(CBaseEntity *pEnemy);
|
|
bool QueryHearSound(CSound *pSound);
|
|
bool IsLightDamage(const CTakeDamageInfo &info);
|
|
bool CreateBehaviors(void);
|
|
bool ShouldHearBugbait(void) { return (m_bIgnoreBugbait == false); }
|
|
int SelectSchedule(void);
|
|
|
|
void Touch(CBaseEntity *pOther);
|
|
|
|
virtual int RangeAttack1Conditions(float flDot, float flDist);
|
|
virtual int MeleeAttack1Conditions(float flDot, float flDist);
|
|
virtual int MeleeAttack2Conditions(float flDot, float flDist);
|
|
virtual int GetSoundInterests(void) {
|
|
return (BaseClass::GetSoundInterests()) |
|
|
(SOUND_DANGER | SOUND_PHYSICS_DANGER | SOUND_THUMPER |
|
|
SOUND_BUGBAIT);
|
|
}
|
|
virtual bool IsHeavyDamage(const CTakeDamageInfo &info);
|
|
|
|
Class_T Classify(void) { return CLASS_ANTLION; }
|
|
|
|
void Event_Killed(const CTakeDamageInfo &info);
|
|
bool FValidateHintType(CAI_Hint *pHint);
|
|
void GatherEnemyConditions(CBaseEntity *pEnemy);
|
|
|
|
bool IsAllied(void);
|
|
bool ShouldGib(const CTakeDamageInfo &info);
|
|
bool CorpseGib(const CTakeDamageInfo &info);
|
|
|
|
float GetMaxJumpSpeed() const { return 1024.0f; }
|
|
|
|
void SetFightTarget(CBaseEntity *pTarget);
|
|
void InputFightToPosition(inputdata_t &inputdata);
|
|
void InputStopFightToPosition(inputdata_t &inputdata);
|
|
void InputJumpAtTarget(inputdata_t &inputdata);
|
|
|
|
void SetFollowTarget(CBaseEntity *pTarget);
|
|
int TranslateSchedule(int scheduleType);
|
|
|
|
virtual Activity NPC_TranslateActivity(Activity baseAct);
|
|
|
|
bool ShouldResumeFollow(void);
|
|
bool ShouldAbandonFollow(void);
|
|
|
|
void SetMoveState(AntlionMoveState_e state);
|
|
int ChooseMoveSchedule(void);
|
|
|
|
DECLARE_DATADESC();
|
|
|
|
bool m_bStartBurrowed;
|
|
float m_flNextJumpPushTime;
|
|
|
|
void SetParentSpawnerName(const char *szName) {
|
|
m_strParentSpawner = MAKE_STRING(szName);
|
|
}
|
|
const char *GetParentSpawnerName(void) {
|
|
return STRING(m_strParentSpawner);
|
|
}
|
|
|
|
virtual void StopLoopingSounds(void);
|
|
bool AllowedToBePushed(void);
|
|
|
|
virtual Vector BodyTarget(const Vector &posSrc, bool bNoisy = true);
|
|
virtual float GetAutoAimRadius() { return 36.0f; }
|
|
|
|
void ClearBurrowPoint(const Vector &origin);
|
|
|
|
void Flip(bool bZapped = false);
|
|
|
|
bool CanBecomeRagdoll();
|
|
|
|
virtual void NotifyDeadFriend(CBaseEntity *pFriend);
|
|
|
|
private:
|
|
inline CBaseEntity *EntityToWatch(void);
|
|
void UpdateHead(void);
|
|
|
|
bool FindChasePosition(const Vector &targetPos, Vector &result);
|
|
bool GetGroundPosition(const Vector &testPos, Vector &result);
|
|
bool GetPathToSoundFleePoint(int soundType);
|
|
inline bool IsFlipped(void);
|
|
|
|
void Burrow(void);
|
|
void Unburrow(void);
|
|
|
|
void InputUnburrow(inputdata_t &inputdata);
|
|
void InputBurrow(inputdata_t &inputdata);
|
|
void InputBurrowAway(inputdata_t &inputdata);
|
|
void InputDisableJump(inputdata_t &inputdata);
|
|
void InputEnableJump(inputdata_t &inputdata);
|
|
void InputIgnoreBugbait(inputdata_t &inputdata);
|
|
void InputHearBugbait(inputdata_t &inputdata);
|
|
|
|
bool FindBurrow(const Vector &origin, float distance, int type,
|
|
bool excludeNear = true);
|
|
void CreateDust(bool placeDecal = true);
|
|
|
|
bool ValidBurrowPoint(const Vector &point);
|
|
bool CheckLanding(void);
|
|
bool Alone(void);
|
|
bool CheckAlertRadius(void);
|
|
bool ShouldJump(void);
|
|
|
|
void MeleeAttack(float distance, float damage, QAngle &viewPunch,
|
|
Vector &shove);
|
|
void SetWings(bool state);
|
|
void StartJump(void);
|
|
void LockJumpNode(void);
|
|
|
|
bool IsUnusableNode(int iNodeID, CAI_Hint *pHint);
|
|
|
|
bool OnObstructionPreSteer(AILocalMoveGoal_t *pMoveGoal, float distClear,
|
|
AIMoveResult_t *pResult);
|
|
|
|
void ManageFleeCapabilities(bool bEnable);
|
|
|
|
int SelectFailSchedule(int failedSchedule, int failedTask,
|
|
AI_TaskFailureCode_t taskFailCode);
|
|
bool IsFirmlyOnGround(void);
|
|
void CascadePush(const Vector &vecForce);
|
|
|
|
virtual bool CanRunAScriptedNPCInteraction(bool bForced = false);
|
|
|
|
virtual void Ignite(float flFlameLifetime, bool bNPCOnly, float flSize,
|
|
bool bCalledByLevelDesigner);
|
|
virtual bool GetSpitVector(const Vector &vecStartPos,
|
|
const Vector &vecTarget, Vector *vecOut);
|
|
virtual bool InnateWeaponLOSCondition(const Vector &ownerPos,
|
|
const Vector &targetPos,
|
|
bool bSetConditions);
|
|
virtual bool FCanCheckAttacks(void);
|
|
|
|
bool SeenEnemyWithinTime(float flTime);
|
|
void DelaySquadAttack(float flDuration);
|
|
|
|
#if HL2_EPISODIC
|
|
void DoPoisonBurst();
|
|
#endif
|
|
|
|
float m_flIdleDelay;
|
|
float m_flBurrowTime;
|
|
float m_flJumpTime;
|
|
float m_flAlertRadius;
|
|
|
|
float m_flPounceTime;
|
|
int m_iUnBurrowAttempts;
|
|
int m_iContext; // for FValidateHintType context
|
|
|
|
Vector
|
|
m_vecSaveSpitVelocity; // Saved when we start to attack and used if we
|
|
// failed to get a clear shot once we release
|
|
|
|
CAI_AntlionFollowBehavior m_FollowBehavior;
|
|
CAI_AssaultBehavior m_AssaultBehavior;
|
|
|
|
AntlionMoveState_e m_MoveState;
|
|
|
|
COutputEvent
|
|
m_OnReachFightGoal; // Reached our scripted destination to fight to
|
|
COutputEvent m_OnUnBurrowed; // Unburrowed
|
|
|
|
Vector m_vecSavedJump;
|
|
Vector m_vecLastJumpAttempt;
|
|
|
|
float m_flIgnoreSoundTime; // Sound time to ignore if earlier than
|
|
float m_flNextAcknowledgeTime; // Next time an antlion can make an
|
|
// acknowledgement noise
|
|
float m_flSuppressFollowTime; // Amount of time to suppress our follow time
|
|
float m_flObeyFollowTime; // A range of time the antlions must be obedient
|
|
|
|
Vector m_vecHeardSound;
|
|
bool m_bHasHeardSound;
|
|
bool m_bAgitatedSound; // Playing agitated sound?
|
|
bool m_bWingsOpen; // Are the wings open?
|
|
bool m_bIgnoreBugbait; // If the antlion should ignore bugbait sounds
|
|
string_t m_strParentSpawner; // Name of our spawner
|
|
|
|
EHANDLE m_hFollowTarget;
|
|
EHANDLE m_hFightGoalTarget;
|
|
float m_flEludeDistance; // Distance until the antlion will consider
|
|
// himself "eluded" if so flagged
|
|
bool m_bLeapAttack;
|
|
bool m_bDisableJump;
|
|
float m_flTimeDrown;
|
|
float m_flTimeDrownSplash;
|
|
bool m_bDontExplode; // Suppresses worker poison burst when drowning,
|
|
// failing to unburrow, etc.
|
|
bool m_bLoopingStarted;
|
|
bool m_bSuppressUnburrowEffects; // Don't kick up dust when spawning
|
|
#if HL2_EPISODIC
|
|
bool m_bHasDoneAirAttack; ///< only allowed to apply this damage once per
|
|
///< glide
|
|
#endif
|
|
|
|
bool m_bForcedStuckJump;
|
|
int m_nBodyBone;
|
|
|
|
// Used to trigger a heavy damage interrupt if sustained damage is taken
|
|
int m_nSustainedDamage;
|
|
float m_flLastDamageTime;
|
|
float m_flZapDuration;
|
|
|
|
protected:
|
|
int m_poseHead_Yaw, m_poseHead_Pitch;
|
|
virtual void PopulatePoseParameters(void);
|
|
|
|
private:
|
|
HSOUNDSCRIPTHANDLE m_hFootstep;
|
|
|
|
DEFINE_CUSTOM_AI;
|
|
|
|
//==================================================
|
|
// AntlionConditions
|
|
//==================================================
|
|
|
|
enum {
|
|
COND_ANTLION_FLIPPED = LAST_SHARED_CONDITION,
|
|
COND_ANTLION_ON_NPC,
|
|
COND_ANTLION_CAN_JUMP,
|
|
COND_ANTLION_FOLLOW_TARGET_TOO_FAR,
|
|
COND_ANTLION_RECEIVED_ORDERS,
|
|
COND_ANTLION_IN_WATER,
|
|
COND_ANTLION_CAN_JUMP_AT_TARGET,
|
|
COND_ANTLION_SQUADMATE_KILLED
|
|
};
|
|
|
|
//==================================================
|
|
// AntlionSchedules
|
|
//==================================================
|
|
|
|
enum {
|
|
SCHED_ANTLION_CHASE_ENEMY_BURROW = LAST_SHARED_SCHEDULE,
|
|
SCHED_ANTLION_JUMP,
|
|
SCHED_ANTLION_RUN_TO_BURROW_IN,
|
|
SCHED_ANTLION_BURROW_IN,
|
|
SCHED_ANTLION_BURROW_WAIT,
|
|
SCHED_ANTLION_BURROW_OUT,
|
|
SCHED_ANTLION_WAIT_FOR_UNBORROW_TRIGGER,
|
|
SCHED_ANTLION_WAIT_FOR_CLEAR_UNBORROW,
|
|
SCHED_ANTLION_WAIT_UNBORROW,
|
|
SCHED_ANTLION_FLEE_THUMPER,
|
|
SCHED_ANTLION_CHASE_BUGBAIT,
|
|
SCHED_ANTLION_FLIP,
|
|
SCHED_ANTLION_DISMOUNT_NPC,
|
|
SCHED_ANTLION_RUN_TO_FIGHT_GOAL,
|
|
SCHED_ANTLION_RUN_TO_FOLLOW_GOAL,
|
|
SCHED_ANTLION_BUGBAIT_IDLE_STAND,
|
|
SCHED_ANTLION_BURROW_AWAY,
|
|
SCHED_ANTLION_FLEE_PHYSICS_DANGER,
|
|
SCHED_ANTLION_POUNCE,
|
|
SCHED_ANTLION_POUNCE_MOVING,
|
|
SCHED_ANTLION_DROWN,
|
|
SCHED_ANTLION_WORKER_RANGE_ATTACK1,
|
|
SCHED_ANTLION_WORKER_RUN_RANDOM,
|
|
SCHED_ANTLION_TAKE_COVER_FROM_ENEMY,
|
|
SCHED_ANTLION_ZAP_FLIP,
|
|
SCHED_ANTLION_WORKER_FLANK_RANDOM,
|
|
SCHED_ANTLION_TAKE_COVER_FROM_SAVEPOSITION
|
|
};
|
|
|
|
//==================================================
|
|
// AntlionTasks
|
|
//==================================================
|
|
|
|
enum {
|
|
TASK_ANTLION_SET_CHARGE_GOAL = LAST_SHARED_TASK,
|
|
TASK_ANTLION_FIND_BURROW_IN_POINT,
|
|
TASK_ANTLION_FIND_BURROW_OUT_POINT,
|
|
TASK_ANTLION_BURROW,
|
|
TASK_ANTLION_UNBURROW,
|
|
TASK_ANTLION_VANISH,
|
|
TASK_ANTLION_BURROW_WAIT,
|
|
TASK_ANTLION_CHECK_FOR_UNBORROW,
|
|
TASK_ANTLION_JUMP,
|
|
TASK_ANTLION_WAIT_FOR_TRIGGER,
|
|
TASK_ANTLION_GET_THUMPER_ESCAPE_PATH,
|
|
TASK_ANTLION_GET_PATH_TO_BUGBAIT,
|
|
TASK_ANTLION_FACE_BUGBAIT,
|
|
TASK_ANTLION_DISMOUNT_NPC,
|
|
TASK_ANTLION_REACH_FIGHT_GOAL,
|
|
TASK_ANTLION_GET_PHYSICS_DANGER_ESCAPE_PATH,
|
|
TASK_ANTLION_FACE_JUMP,
|
|
TASK_ANTLION_DROWN,
|
|
TASK_ANTLION_GET_PATH_TO_RANDOM_NODE,
|
|
TASK_ANTLION_FIND_COVER_FROM_SAVEPOSITION,
|
|
};
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Shield
|
|
//-----------------------------------------------------------------------------
|
|
class CAntlionRepellant : public CPointEntity {
|
|
DECLARE_DATADESC();
|
|
|
|
public:
|
|
DECLARE_CLASS(CAntlionRepellant, CPointEntity);
|
|
~CAntlionRepellant();
|
|
|
|
public:
|
|
void Spawn(void);
|
|
void InputEnable(inputdata_t &inputdata);
|
|
void InputDisable(inputdata_t &inputdata);
|
|
float GetRadius(void);
|
|
void SetRadius(float flRadius) { m_flRepelRadius = flRadius; }
|
|
|
|
static bool IsPositionRepellantFree(Vector vDesiredPos);
|
|
|
|
void OnRestore(void);
|
|
|
|
private:
|
|
float m_flRepelRadius;
|
|
bool m_bEnabled;
|
|
};
|
|
|
|
extern bool IsAntlion(CBaseEntity *pEntity);
|
|
extern bool IsAntlionWorker(CBaseEntity *pEntity);
|
|
|
|
#ifdef HL2_EPISODIC
|
|
extern float AntlionWorkerBurstRadius(void);
|
|
#endif // HL2_EPISODIC
|
|
|
|
#endif // NPC_ANTLION_H
|