//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $Workfile: $ // $Date: $ // $NoKeywords: $ //=============================================================================// #ifndef TALKNPC_H #define TALKNPC_H #ifdef POSIX #undef time #include #endif #ifndef _XBOX #undef min #undef max #pragma warning(push) #include #pragma warning(pop) #endif #ifdef _WIN32 #pragma once #endif // the include monkey's with the MAX() define, unbreak it #undef MINMAX_H #include "minmax.h" #include "ai_playerally.h" #include "soundflags.h" #include "ai_basenpc.h" #include "ai_behavior.h" #include "ai_behavior_follow.h" #include "ai_default.h" #include "ai_schedule.h" #include "ai_speech.h" #include "ai_task.h" #include "tier0/memdbgon.h" //========================================================= // Talking NPC base class // Used for scientists and barneys //========================================================= #define TLK_CFRIENDS 4 //============================================================================= // >> CNPCSimpleTalker //============================================================================= #define MONOLOGNAME_LEN \ 16 // sentence names passed as monolog may be no longer than this. #define AI_SP_START_MONOLOG '~' #define AI_SP_MONOLOG_LINE '@' class CNPCSimpleTalker; class CNPCSimpleTalkerExpresser : public CAI_ComponentWithOuter { public: CNPCSimpleTalkerExpresser(CNPCSimpleTalker *pOuter) : CAI_ComponentWithOuter(pOuter) { EndMonolog(); } virtual int SpeakRawSentence(const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL); // -------------------------------- // // Monologue operations // bool HasMonolog(void) { return m_iMonologIndex != -1; }; void BeginMonolog(char *pszSentenceName, CBaseEntity *pListener); void EndMonolog(void); void SpeakMonolog(void); void SuspendMonolog(float flInterval); void ResumeMonolog(void); CBaseEntity *GetMonologueTarget() { return m_hMonologTalkTarget.Get(); } // -------------------------------- // // Monologue data // char m_szMonologSentence[MONOLOGNAME_LEN]; // The name of the sentence group // for the monolog I'm speaking. int m_iMonologIndex; // Which sentence from the group I should be speaking. bool m_fMonologSuspended; EHANDLE m_hMonologTalkTarget; // Who I'm trying to deliver my monolog to. DECLARE_SIMPLE_DATADESC(); }; //------------------------------------- class CNPCSimpleTalker : public CAI_PlayerAlly { DECLARE_CLASS(CNPCSimpleTalker, CAI_PlayerAlly); public: void Precache(void); virtual bool KeyValue(const char *szKeyName, const char *szValue); virtual CAI_Expresser *CreateExpresser() { return new CNPCSimpleTalkerExpresser(this); } virtual void StartFollowing(CBaseEntity *pLeader) { m_FollowBehavior.SetFollowTarget(pLeader); DeferSchedulingToBehavior(&m_FollowBehavior); } virtual void StopFollowing() { m_FollowBehavior.SetFollowTarget(NULL); DeferSchedulingToBehavior(NULL); } CBaseEntity *GetFollowTarget(void) { return m_FollowBehavior.GetFollowTarget(); } virtual void OnChangeRunningBehavior(CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior); bool OnBehaviorChangeStatus(CAI_BehaviorBase *pBehavior, bool fCanFinishSchedule); int PlayScriptedSentence(const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, bool bConcurrent, CBaseEntity *pListener); virtual void FollowerUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); void Event_Killed(const CTakeDamageInfo &info); int OnTakeDamage_Alive(const CTakeDamageInfo &info); bool CreateBehaviors() { AddBehavior(&m_FollowBehavior); return BaseClass::CreateBehaviors(); } void BuildScheduleTestBits(void); void PrescheduleThink(void); virtual int SelectSchedule(void); virtual int SelectNonCombatSpeechSchedule(); void StartTask(const Task_t *pTask); void RunTask(const Task_t *pTask); void HandleAnimEvent(animevent_t *pEvent); Activity NPC_TranslateActivity(Activity newActivity); virtual void OnStartingFollow(CBaseEntity *pTarget); virtual void OnStoppingFollow(CBaseEntity *pTarget); virtual void DeferAllIdleSpeech(float flDelay, CAI_BaseNPC *pIgnore = NULL); bool ShouldSpeakRandom(int iChance, float flModifier); // For following virtual void DeclineFollowing(void) {} void LimitFollowers(CBaseEntity *pPlayer, int maxFollowers); float GetUseTime() const { return m_useTime; } //========================================================= // TalkNPC schedules //========================================================= enum { SCHED_TALKER_IDLE_RESPONSE = BaseClass::NEXT_SCHEDULE, SCHED_TALKER_IDLE_SPEAK, SCHED_TALKER_IDLE_HELLO, SCHED_TALKER_IDLE_STOP_SHOOTING, SCHED_TALKER_IDLE_WATCH_CLIENT, SCHED_TALKER_IDLE_WATCH_CLIENT_STARE, SCHED_TALKER_IDLE_EYE_CONTACT, SCHED_TALKER_BETRAYED, // !ALWAYS LAST! NEXT_SCHEDULE, }; //========================================================= // TalkNPC tasks //========================================================= enum { TASK_TALKER_RESPOND = BaseClass::NEXT_TASK, // say my response TASK_TALKER_SPEAK, // question or remark TASK_TALKER_HELLO, // Try to say hello to player TASK_TALKER_BETRAYED, // Player killed an ally TASK_TALKER_HEADRESET, // reset head position TASK_TALKER_STOPSHOOTING, // tell player to stop shooting friend TASK_TALKER_STARE, // let the player know I know he's staring at me. TASK_TALKER_LOOK_AT_CLIENT, // faces player if not moving and not // talking and in idle. TASK_TALKER_CLIENT_STARE, // same as look at client, but says something // if the player stares. TASK_TALKER_EYECONTACT, // maintain eyecontact with person who I'm // talking to TASK_TALKER_IDEALYAW, // set ideal yaw to face who I'm talking to TASK_FIND_LOCK_HINTNODE_HEALTH, // Find & lock a nearby healthkit // hintnode to heal myself at TASK_TALKER_WAIT_FOR_SEMAPHORE, // !ALWAYS LAST! NEXT_TASK, }; // private: virtual bool IsValidSpeechTarget(int flags, CBaseEntity *pEntity); CBaseEntity *FindNearestFriend(bool fPlayer); bool IsOkToSpeak(void); void SayHelloToPlayer(CBaseEntity *pPlayer); virtual bool CanSayHello(void); virtual int FIdleHello(void); // Inputs void InputIdleRespond(inputdata_t &inputdata); // Conversations / communication void IdleRespond(void); int FIdleSpeak(void); void FIdleSpeakWhileMoving(void); int FIdleStare(void); bool SpeakQuestionFriend(CBaseEntity *pFriend); bool SpeakAnswerFriend(CBaseEntity *pFriend); void TrySmellTalk(void); virtual void SetAnswerQuestion(CNPCSimpleTalker *pSpeaker); bool ShouldSuspendMonolog(void); bool ShouldResumeMonolog(void); void OnResumeMonolog() { Speak(TLK_RESUME); } int m_nSpeak; // number of times initiated talking float m_flNextIdleSpeechTime; static char *m_szFriends[TLK_CFRIENDS]; // array of friend names CBaseEntity *EnumFriends(CBaseEntity *pentPrevious, int listNumber, bool bTrace); virtual int FriendNumber(int arrayNumber) { return arrayNumber; } void ShutUpFriends(void); void AlertFriends(CBaseEntity *pKiller); string_t m_iszUse; // Custom +USE sentence group (follow) string_t m_iszUnUse; // Custom +USE sentence group (stop following) protected: CAI_FollowBehavior m_FollowBehavior; float m_useTime; // Don't allow +USE until this time //--------------------------------- DECLARE_DATADESC(); #ifndef _XBOX DEFINE_CUSTOM_AI; #else public: DEFINE_CUSTOM_AI; private: #endif }; #include "tier0/memdbgoff.h" #endif // TALKNPC_H