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

442 lines
14 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The downtrodden citizens of City 17. Timid when unarmed, they will
// rise up against their Combine oppressors when given a
//weapon.
//
//=============================================================================//
#ifndef NPC_CITIZEN_H
#define NPC_CITIZEN_H
#include "npc_playercompanion.h"
#include "ai_behavior_functank.h"
struct SquadCandidate_t;
//-----------------------------------------------------------------------------
//
// CLASS: CNPC_Citizen
//
//-----------------------------------------------------------------------------
//-------------------------------------
// Spawnflags
//-------------------------------------
#define SF_CITIZEN_FOLLOW \
(1 << 16) // 65536 follow the player as soon as I spawn.
#define SF_CITIZEN_MEDIC (1 << 17) // 131072
#define SF_CITIZEN_RANDOM_HEAD (1 << 18) // 262144
#define SF_CITIZEN_AMMORESUPPLIER (1 << 19) // 524288
#define SF_CITIZEN_NOT_COMMANDABLE (1 << 20) // 1048576
#define SF_CITIZEN_IGNORE_SEMAPHORE \
(1 << 21) // 2097152 Work outside the speech semaphore system
#define SF_CITIZEN_RANDOM_HEAD_MALE (1 << 22) // 4194304
#define SF_CITIZEN_RANDOM_HEAD_FEMALE (1 << 23) // 8388608
#define SF_CITIZEN_USE_RENDER_BOUNDS (1 << 24) // 16777216
//-------------------------------------
// Animation events
//-------------------------------------
enum CitizenType_t {
CT_DEFAULT,
CT_DOWNTRODDEN,
CT_REFUGEE,
CT_REBEL,
CT_UNIQUE
};
//-----------------------------------------------------------------------------
// Citizen expression types
//-----------------------------------------------------------------------------
enum CitizenExpressionTypes_t {
CIT_EXP_UNASSIGNED, // Defaults to this, selects other in spawn.
CIT_EXP_SCARED,
CIT_EXP_NORMAL,
CIT_EXP_ANGRY,
CIT_EXP_LAST_TYPE,
};
//-------------------------------------
class CNPC_Citizen : public CNPC_PlayerCompanion {
DECLARE_CLASS(CNPC_Citizen, CNPC_PlayerCompanion);
public:
CNPC_Citizen() : m_iHead(-1) {}
//---------------------------------
bool CreateBehaviors();
void Precache();
void PrecacheAllOfType(CitizenType_t);
void Spawn();
void PostNPCInit();
virtual void SelectModel();
void SelectExpressionType();
void Activate();
virtual void OnGivenWeapon(CBaseCombatWeapon *pNewWeapon);
void FixupMattWeapon();
#ifdef HL2_EPISODIC
virtual float GetJumpGravity() const { return 1.8f; }
#endif // HL2_EPISODIC
void OnRestore();
//---------------------------------
string_t GetModelName() const;
Class_T Classify();
bool ShouldAlwaysThink();
//---------------------------------
// Behavior
//---------------------------------
bool ShouldBehaviorSelectSchedule(CAI_BehaviorBase *pBehavior);
void GatherConditions();
void PredictPlayerPush();
void PrescheduleThink();
void BuildScheduleTestBits();
bool FInViewCone(CBaseEntity *pEntity);
int SelectFailSchedule(int failedSchedule, int failedTask,
AI_TaskFailureCode_t taskFailCode);
int SelectSchedule();
int SelectSchedulePriorityAction();
int SelectScheduleHeal();
int SelectScheduleRetrieveItem();
int SelectScheduleNonCombat();
int SelectScheduleManhackCombat();
int SelectScheduleCombat();
bool ShouldDeferToFollowBehavior();
int TranslateSchedule(int scheduleType);
bool ShouldAcceptGoal(CAI_BehaviorBase *pBehavior, CAI_GoalEntity *pGoal);
void OnClearGoal(CAI_BehaviorBase *pBehavior, CAI_GoalEntity *pGoal);
void StartTask(const Task_t *pTask);
void RunTask(const Task_t *pTask);
Activity NPC_TranslateActivity(Activity eNewActivity);
void HandleAnimEvent(animevent_t *pEvent);
void TaskFail(AI_TaskFailureCode_t code);
void PickupItem(CBaseEntity *pItem);
void SimpleUse(CBaseEntity *pActivator, CBaseEntity *pCaller,
USE_TYPE useType, float value);
bool IgnorePlayerPushing(void);
int DrawDebugTextOverlays(void);
virtual const char *SelectRandomExpressionForState(NPC_STATE state);
//---------------------------------
// Combat
//---------------------------------
bool OnBeginMoveAndShoot();
void OnEndMoveAndShoot();
virtual bool UseAttackSquadSlots() { return false; }
void LocateEnemySound();
bool IsManhackMeleeCombatant();
Vector GetActualShootPosition(const Vector &shootOrigin);
void OnChangeActiveWeapon(CBaseCombatWeapon *pOldWeapon,
CBaseCombatWeapon *pNewWeapon);
bool ShouldLookForBetterWeapon();
//---------------------------------
// Damage handling
//---------------------------------
int OnTakeDamage_Alive(const CTakeDamageInfo &info);
//---------------------------------
// Commander mode
//---------------------------------
bool IsCommandable();
bool IsPlayerAlly(CBasePlayer *pPlayer = NULL);
bool CanJoinPlayerSquad();
bool WasInPlayerSquad();
bool HaveCommandGoal() const;
bool IsCommandMoving();
bool ShouldAutoSummon();
bool IsValidCommandTarget(CBaseEntity *pTarget);
bool NearCommandGoal();
bool VeryFarFromCommandGoal();
bool TargetOrder(CBaseEntity *pTarget, CAI_BaseNPC **Allies, int numAllies);
void MoveOrder(const Vector &vecDest, CAI_BaseNPC **Allies, int numAllies);
void OnMoveOrder();
void CommanderUse(CBaseEntity *pActivator, CBaseEntity *pCaller,
USE_TYPE useType, float value);
bool ShouldSpeakRadio(CBaseEntity *pListener);
void OnMoveToCommandGoalFailed();
void AddToPlayerSquad();
void RemoveFromPlayerSquad();
void TogglePlayerSquadState();
void UpdatePlayerSquad();
static int __cdecl PlayerSquadCandidateSortFunc(const SquadCandidate_t *,
const SquadCandidate_t *);
void FixupPlayerSquad();
void ClearFollowTarget();
void UpdateFollowCommandPoint();
bool IsFollowingCommandPoint();
CAI_BaseNPC *GetSquadCommandRepresentative();
void SetSquad(CAI_Squad *pSquad);
void AddInsignia();
void RemoveInsignia();
bool SpeakCommandResponse(AIConcept_t concept,
const char *modifiers = NULL);
//---------------------------------
// Scanner interaction
//---------------------------------
float GetNextScannerInspectTime() { return m_fNextInspectTime; }
void SetNextScannerInspectTime(float flTime) {
m_fNextInspectTime = flTime;
}
bool HandleInteraction(int interactionType, void *data,
CBaseCombatCharacter *sourceEnt);
//---------------------------------
// Hints
//---------------------------------
bool FValidateHintType(CAI_Hint *pHint);
//---------------------------------
// Special abilities
//---------------------------------
bool IsMedic() { return HasSpawnFlags(SF_CITIZEN_MEDIC); }
bool IsAmmoResupplier() { return HasSpawnFlags(SF_CITIZEN_AMMORESUPPLIER); }
bool CanHeal();
bool ShouldHealTarget(CBaseEntity *pTarget, bool bActiveUse = false);
#if HL2_EPISODIC
bool ShouldHealTossTarget(CBaseEntity *pTarget, bool bActiveUse = false);
#endif
void Heal();
bool ShouldLookForHealthItem();
#if HL2_EPISODIC
void TossHealthKit(
CBaseCombatCharacter *pThrowAt,
const Vector &offset); // create a healthkit and throw it at someone
void InputForceHealthKitToss(inputdata_t &inputdata);
#endif
//---------------------------------
// Inputs
//---------------------------------
void InputRemoveFromPlayerSquad(inputdata_t &inputdata) {
RemoveFromPlayerSquad();
}
void InputStartPatrolling(inputdata_t &inputdata);
void InputStopPatrolling(inputdata_t &inputdata);
void InputSetCommandable(inputdata_t &inputdata);
void InputSetMedicOn(inputdata_t &inputdata);
void InputSetMedicOff(inputdata_t &inputdata);
void InputSetAmmoResupplierOn(inputdata_t &inputdata);
void InputSetAmmoResupplierOff(inputdata_t &inputdata);
void InputSpeakIdleResponse(inputdata_t &inputdata);
//---------------------------------
// Sounds & speech
//---------------------------------
void FearSound(void);
void DeathSound(const CTakeDamageInfo &info);
bool UseSemaphore(void);
virtual void OnChangeRunningBehavior(CAI_BehaviorBase *pOldBehavior,
CAI_BehaviorBase *pNewBehavior);
private:
//-----------------------------------------------------
// Conditions, Schedules, Tasks
//-----------------------------------------------------
enum {
COND_CIT_PLAYERHEALREQUEST = BaseClass::NEXT_CONDITION,
COND_CIT_COMMANDHEAL,
COND_CIT_HURTBYFIRE,
COND_CIT_START_INSPECTION,
SCHED_CITIZEN_PLAY_INSPECT_ACTIVITY = BaseClass::NEXT_SCHEDULE,
SCHED_CITIZEN_HEAL,
SCHED_CITIZEN_RANGE_ATTACK1_RPG,
SCHED_CITIZEN_PATROL,
SCHED_CITIZEN_MOURN_PLAYER,
SCHED_CITIZEN_SIT_ON_TRAIN,
SCHED_CITIZEN_STRIDER_RANGE_ATTACK1_RPG,
#ifdef HL2_EPISODIC
SCHED_CITIZEN_HEAL_TOSS,
#endif
TASK_CIT_HEAL = BaseClass::NEXT_TASK,
TASK_CIT_RPG_AUGER,
TASK_CIT_PLAY_INSPECT_SEQUENCE,
TASK_CIT_SIT_ON_TRAIN,
TASK_CIT_LEAVE_TRAIN,
TASK_CIT_SPEAK_MOURNING,
#ifdef HL2_EPISODIC
TASK_CIT_HEAL_TOSS,
#endif
};
//-----------------------------------------------------
int m_nInspectActivity;
float m_flNextFearSoundTime;
float m_flStopManhackFlinch;
float m_fNextInspectTime; // Next time I'm allowed to get inspected by a
// scanner
float m_flPlayerHealTime;
float m_flNextHealthSearchTime; // Next time I'm allowed to look for a
// healthkit
float m_flAllyHealTime;
float m_flPlayerGiveAmmoTime;
string_t m_iszAmmoSupply;
int m_iAmmoAmount;
bool m_bRPGAvoidPlayer;
bool m_bShouldPatrol;
string_t m_iszOriginalSquad;
float m_flTimeJoinedPlayerSquad;
bool m_bWasInPlayerSquad;
float m_flTimeLastCloseToPlayer;
string_t m_iszDenyCommandConcept;
CSimpleSimTimer m_AutoSummonTimer;
Vector m_vAutoSummonAnchor;
CitizenType_t m_Type;
CitizenExpressionTypes_t m_ExpressionType;
int m_iHead;
static CSimpleSimTimer gm_PlayerSquadEvaluateTimer;
float m_flTimePlayerStare; // The game time at which the player started
// staring at me.
float m_flTimeNextHealStare; // Next time I'm allowed to heal a player who
// is staring at me.
//-----------------------------------------------------
// Outputs
//-----------------------------------------------------
COutputEvent m_OnJoinedPlayerSquad;
COutputEvent m_OnLeftPlayerSquad;
COutputEvent m_OnFollowOrder;
COutputEvent m_OnStationOrder;
COutputEvent m_OnPlayerUse;
COutputEvent m_OnNavFailBlocked;
//-----------------------------------------------------
CAI_FuncTankBehavior m_FuncTankBehavior;
CHandle<CAI_FollowGoal> m_hSavedFollowGoalEnt;
bool m_bNotifyNavFailBlocked;
bool m_bNeverLeavePlayerSquad; // Don't leave the player squad unless
// killed, or removed via Entity I/O.
//-----------------------------------------------------
DECLARE_DATADESC();
#ifdef _XBOX
protected:
#endif
DEFINE_CUSTOM_AI;
};
//---------------------------------------------------------
//---------------------------------------------------------
inline bool CNPC_Citizen::NearCommandGoal() {
const float flDistSqr = COMMAND_GOAL_TOLERANCE * COMMAND_GOAL_TOLERANCE;
return ((GetAbsOrigin() - GetCommandGoal()).LengthSqr() <= flDistSqr);
}
//---------------------------------------------------------
//---------------------------------------------------------
inline bool CNPC_Citizen::VeryFarFromCommandGoal() {
const float flDistSqr = (12 * 50) * (12 * 50);
return ((GetAbsOrigin() - GetCommandGoal()).LengthSqr() > flDistSqr);
}
//==============================================================================
// CITIZEN PLAYER-RESPONSE SYSTEM
//
// NOTE: This system is obsolete, and left here for legacy support.
// It has been superseded by the ai_eventresponse system.
//
//==============================================================================
#define CITIZEN_RESPONSE_DISTANCE \
768 // Maximum distance for responding citizens
#define CITIZEN_RESPONSE_REFIRE_TIME \
15.0 // Time after giving a response before giving any more
#define CITIZEN_RESPONSE_GIVEUP_TIME \
4.0 // Time after a response trigger was fired before discarding it without
// responding
enum citizenresponses_t {
CR_PLAYER_SHOT_GUNSHIP, // Player has shot the gunship with a bullet weapon
CR_PLAYER_KILLED_GUNSHIP, // Player has destroyed the gunship
CR_VITALNPC_DIED, // Mapmaker specified that an NPC that was vital has died
// Add new responses here
MAX_CITIZEN_RESPONSES,
};
//-------------------------------------
class CCitizenResponseSystem : public CBaseEntity {
DECLARE_CLASS(CCitizenResponseSystem, CBaseEntity);
public:
DECLARE_DATADESC();
void Spawn();
void OnRestore();
void AddResponseTrigger(citizenresponses_t iTrigger);
void ResponseThink();
//---------------------------------
// Inputs
//---------------------------------
void InputResponseVitalNPC(inputdata_t &inputdata);
private:
float m_flResponseAddedTime
[MAX_CITIZEN_RESPONSES]; // Time at which the response was added. 0 if
// we have no response.
float m_flNextResponseTime;
};
//-------------------------------------
class CSquadInsignia : public CBaseAnimating {
DECLARE_CLASS(CSquadInsignia, CBaseAnimating);
void Spawn();
};
//-------------------------------------
CCitizenResponseSystem *GetCitizenResponse();
//-----------------------------------------------------------------------------
#endif // NPC_CITIZEN_H