This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

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