/*** * * Copyright (c) 1996-2002, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * This source code contains proprietary and confidential information of * Valve LLC and its suppliers. Access to this code is restricted to * persons who have executed a written SDK license with Valve. Any access, * use or distribution of this code by or to any unlicensed person is illegal. * ****/ #ifndef BASEMONSTER_H #define BASEMONSTER_H #include "AI_Target.h" #define AI_CALC_YAW_SPEED -1 #define AI_KEEP_YAW_SPEED -2 // // generic Monster // class CBaseMonster : public CBaseToggle { private: int m_afConditions; public: typedef enum { SCRIPT_PLAYING = 0, // Playing the sequence SCRIPT_WAIT, // Waiting on everyone in the script to be ready SCRIPT_CLEANUP, // Cancelling the script / cleaning up SCRIPT_WALK_TO_MARK, SCRIPT_RUN_TO_MARK, } SCRIPTSTATE; // these fields have been added in the process of reworking the state machine. (sjb) EHANDLE m_hEnemy; // the entity that the monster is fighting. EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach EHANDLE m_hOldEnemy[ MAX_OLD_ENEMIES ]; Vector m_vecOldEnemy[ MAX_OLD_ENEMIES ]; float m_flFieldOfView;// width of monster's field of view ( dot product ) float m_flWaitFinished;// if we're told to wait, this is the time that the wait will be over. float m_flMoveWaitFinished; Activity m_Activity;// what the monster is doing (animation) Activity m_IdealActivity;// monster should switch to this activity int m_LastHitGroup; // the last body region that took damage MONSTERSTATE m_MonsterState;// monster's current state MONSTERSTATE m_IdealMonsterState;// monster should change to this state int m_iTaskStatus; Schedule_t *m_pSchedule; int m_iScheduleIndex; WayPoint_t m_Route[ ROUTE_SIZE ]; // Positions of movement int m_movementGoal; // Goal that defines route int m_iRouteIndex; // index into m_Route[] float m_moveWaitTime; // How long I should wait for something to move Vector m_vecMoveGoal; // kept around for node graph moves, so we know our ultimate goal Activity m_movementActivity; // When moving, set this activity int m_iAudibleList; // first index of a linked list of sounds that the monster can hear. int m_afSoundTypes; Vector m_vecLastPosition;// monster sometimes wants to return to where it started after an operation. int m_iHintNode; // this is the hint node that the monster is moving towards or performing active idle on. int m_afMemory; int m_iMaxHealth;// keeps track of monster's maximum health value (for re-healing, etc) Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) int m_cAmmoLoaded; // how much ammo is in the weapon (used to trigger reload anim sequences) int m_afCapability;// tells us what a monster can/can't do. float m_flNextAttack; // cannot attack again until this time int m_bitsDamageType; // what types of damage has monster (player) taken BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; int m_lastDamageAmount;// how much damage did monster (player) last take // time based damage counters, decr. 1 per 2 seconds int m_bloodColor; // color of blood particless int m_failSchedule; // Schedule type to choose if current schedule fails float m_flHungryTime;// set this is a future time to stop the monster from eating for a while. float m_flDistTooFar; // if enemy farther away than this, bits_COND_ENEMY_TOOFAR set in CheckEnemy float m_flDistLook; // distance monster sees (Default 2048) int m_iTriggerCondition;// for scripted AI, this is the condition that will cause the activation of the monster's TriggerTarget string_t m_iszTriggerTarget;// name of target that should be fired. Vector m_HackedGunPos; // HACK until we can query end of gun int m_iUseAlertAnims; // buz: start in alert state // Scripted sequence Info SCRIPTSTATE m_scriptState; // internal cinematic state CCineMonster *m_pCine; virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; void KeyValue( KeyValueData *pkvd ); // monster use function void EXPORT MonsterUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void EXPORT CorpseUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); // overrideable Monster member functions // LRC- to allow level-designers to change monster allegiances int m_iClass; int m_iPlayerReact; virtual int Classify( void ) { return m_iClass?m_iClass:CLASS_NONE; } virtual int BloodColor( void ) { return m_bloodColor; } virtual CBaseMonster *MyMonsterPointer( void ) { return this; } virtual void Look ( int iDistance );// basic sight function for monsters virtual void RunAI ( void );// core ai function! void RunAnimation( void ); void Listen ( void ); virtual BOOL AllowDecal( entvars_t *pevAttacker ); virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } virtual BOOL ShouldFadeOnDeath( void ); // Basic Monster AI functions virtual float ChangeYaw ( int speed ); float VecToYaw( Vector vecDir ); float DeltaIdealYaw( void ); void CalcFacing( float flInterval ); float ClampYaw( float yawSpeedPerSec, float current, float target, float time ); float CalcIdealYaw( const Vector &vecTarget ); // Run the current or specified timestep worth of rotation void UpdateYaw( int speed = -1 ); void MoveFacing( void ); // ---------------------------------------------------- // Rotational movement (yaw); goal and speed // ---------------------------------------------------- void SetYawSpeed( float yawSpeed ) { pev->yaw_speed = yawSpeed; } float GetYawSpeed( void ) const { return pev->yaw_speed; } float GetIdealYaw( void ) const { return pev->ideal_yaw; } void SetIdealYaw( float idealYaw ) { pev->ideal_yaw = idealYaw; } // Set ideal yaw specified as a vector void SetIdealYaw( const Vector &vecFacing ) { SetIdealYaw( UTIL_VecToYaw( vecFacing )); } // Force the heading to the ideal yaw void SnapYaw( void ) { UpdateYaw( 360 ); } // Set ideal yaw based on a specified target void SetIdealYawToTarget( const Vector &target ); float CalcYawSpeed( void ); void RecalculateYawSpeed( void ); // Set the ideal yaw and run the current or specified timestep worth of rotation. Note // it is not correct to call any "update" variant of these methods more // than once per think cycle void SetIdealYawAndUpdate( float idealYaw, float yawSpeed = AI_CALC_YAW_SPEED ); void SetIdealYawAndUpdate( const Vector &vecFacing, float yawSpeed = AI_CALC_YAW_SPEED ) { SetIdealYawAndUpdate( UTIL_VecToYaw( vecFacing ), yawSpeed ); } void SetIdealYawToTargetAndUpdate( const Vector &target, float yawSpeed = AI_CALC_YAW_SPEED ); float DamageForce( float damage ); void AutoSetSize( void ); // stuff written for new state machine virtual void MonsterThink( void ); void EXPORT CallMonsterThink( void ) { this->MonsterThink(); } virtual int IRelationship ( CBaseEntity *pTarget ); virtual void MonsterInit ( void ); virtual void MonsterInitDead( void ); // Call after animation/pose is set up virtual void BecomeDead( void ); void EXPORT CorpseFallThink( void ); void EXPORT MonsterInitThink ( void ); virtual void StartMonster ( void ); virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone virtual void HandleAnimEvent( MonsterEvent_t *pEvent ); virtual int CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist );// check validity of a straight move through space virtual void Move( float flInterval = 0.1 ); virtual void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ); virtual BOOL ShouldAdvanceRoute( float flWaypointDist ); virtual Activity GetStoppedActivity( void ) { return ACT_IDLE; } virtual void Stop( void ) { m_IdealActivity = GetStoppedActivity(); } // This will stop animation until you call ResetSequenceInfo() at some point in the future inline void StopAnimation( void ) { pev->framerate = 0; } // these functions will survey conditions and set appropriate conditions bits for attack types. virtual BOOL CheckRangeAttack1( float flDot, float flDist ); virtual BOOL CheckRangeAttack2( float flDot, float flDist ); virtual BOOL CheckMeleeAttack1( float flDot, float flDist ); virtual BOOL CheckMeleeAttack2( float flDot, float flDist ); BOOL FHaveSchedule( void ); BOOL FScheduleValid ( void ); void ClearSchedule( void ); BOOL FScheduleDone ( void ); void ChangeSchedule ( Schedule_t *pNewSchedule ); void NextScheduledTask ( void ); Schedule_t *ScheduleInList( const char *pName, Schedule_t **pList, int listCount ); virtual Schedule_t *ScheduleFromName( const char *pName ); static Schedule_t *m_scheduleList[]; void MaintainSchedule ( void ); virtual void StartTask ( Task_t *pTask ); virtual void RunTask ( Task_t *pTask ); virtual Schedule_t *GetScheduleOfType( int Type ); virtual Schedule_t *GetSchedule( void ); virtual void ScheduleChange( void ) {} // virtual int CanPlaySequence( void ) { return ((m_pCine == NULL) && (m_MonsterState == MONSTERSTATE_NONE || m_MonsterState == MONSTERSTATE_IDLE || m_IdealMonsterState == MONSTERSTATE_IDLE)); } virtual int CanPlaySequence( int interruptFlags ); // virtual int CanPlaySequence( BOOL fDisregardState, int interruptLevel ); virtual int CanPlaySentence( BOOL fDisregardState ) { return IsAlive(); } virtual void PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ); virtual void PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ); virtual void SentenceStop( void ); Task_t *GetTask ( void ); virtual MONSTERSTATE GetIdealState ( void ); virtual void SetActivity ( Activity NewActivity ); void SetIdealActivity( Activity NewActivity ); void SetSequenceByName ( char *szSequence ); void SetState ( MONSTERSTATE State ); virtual void ReportAIState( void ); void CheckAttacks ( CBaseEntity *pTarget, float flDist ); virtual int CheckEnemy ( CBaseEntity *pEnemy ); void PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ); BOOL PopEnemy( void ); BOOL FGetNodeRoute ( Vector vecDest ); inline void TaskComplete( void ) { if ( !HasConditions(bits_COND_TASK_FAILED) ) m_iTaskStatus = TASKSTATUS_COMPLETE; } void MovementComplete( void ); inline void TaskFail( void ) { SetConditions(bits_COND_TASK_FAILED); } inline void TaskBegin( void ) { m_iTaskStatus = TASKSTATUS_RUNNING; } int TaskIsRunning( void ); inline int TaskIsComplete( void ) { return (m_iTaskStatus == TASKSTATUS_COMPLETE); } inline int MovementIsComplete( void ) { return (m_movementGoal == MOVEGOAL_NONE); } int IScheduleFlags ( void ); BOOL FRefreshRoute( void ); BOOL FRouteClear ( void ); void RouteSimplify( CBaseEntity *pTargetEnt ); void AdvanceRoute ( float distance ); virtual BOOL FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ); virtual float MaxYawSpeed ( void ); // allows different yaw_speeds for each activity BOOL BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ); virtual BOOL BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ); int RouteClassify( int iMoveFlag ); void InsertWaypoint ( Vector vecLocation, int afMoveFlags ); BOOL FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ); virtual BOOL FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ); virtual BOOL FValidateCover ( const Vector &vecCoverLocation ) { return TRUE; }; virtual float CoverRadius( void ) { return 784; } // Default cover radius virtual BOOL FCanCheckAttacks ( void ); virtual void CheckAmmo( void ) { return; }; virtual int IgnoreConditions ( void ); inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; } inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; } inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; } inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; } virtual BOOL FValidateHintType( short sHint ); int FindHintNode ( void ); virtual BOOL FCanActiveIdle ( void ); void SetTurnActivity ( void ); float FLSoundVolume ( CSound *pSound ); BOOL MoveToNode( Activity movementAct, float waitTime, const Vector &goal ); BOOL MoveToTarget( Activity movementAct, float waitTime ); BOOL MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ); BOOL MoveToEnemy( Activity movementAct, float waitTime ); // Returns the time when the door will be open float OpenDoorAndWait( entvars_t *pevDoor ); virtual int ISoundMask( void ); virtual CSound* PBestSound ( void ); virtual CSound* PBestScent ( void ); virtual float HearingSensitivity( void ) { return 1.0; }; BOOL FBecomeProne ( void ); virtual void BarnacleVictimBitten( entvars_t *pevBarnacle ); virtual void BarnacleVictimReleased( void ); virtual void SetEyePosition ( void ); BOOL FShouldEat( void );// see if a monster is 'hungry' void Eat ( float flFullDuration );// make the monster 'full' for a while. CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); BOOL FacingIdeal( void ); BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. BOOL NoFriendlyFire( void ); BOOL BBoxFlat( void ); // PrescheduleThink virtual void PrescheduleThink( void ) { return; }; virtual BOOL GetEnemy ( void ); // buz: make virtual void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); // combat functions float UpdateTarget ( entvars_t *pevTarget ); virtual Activity GetDeathActivity ( void ); Activity GetSmallFlinchActivity( void ); virtual void Killed( entvars_t *pevAttacker, int iGib ); virtual void GibMonster( void ); BOOL ShouldGibMonster( int iGib ); void CallGibMonster( void ); virtual const char* DamageDecal( int bitsDamageType ); virtual int HasCustomGibs( void ) { return FALSE; } //LRC virtual BOOL HasHumanGibs( void ); virtual BOOL HasAlienGibs( void ); virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled virtual Vector ShootAtEnemy( const Vector &shootOrigin ); // virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) * 0.75 + EyePosition() * 0.25; }; // position to shoot at virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) * 0.5 + EyePosition() * 0.5; }; // buz: fix to allow grunts shoot over obstacles virtual Vector GetGunPosition( void ); virtual int TakeHealth( float flHealth, int bitsDamageType ); virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); virtual int IsMoving( void ) { return m_movementGoal != MOVEGOAL_NONE; } void RouteClear( void ); void RouteNew( void ); virtual void DeathSound ( void ) { return; }; virtual void AlertSound ( void ) { return; }; virtual void IdleSound ( void ) { return; }; virtual void PainSound ( void ) { return; }; virtual void BlockedByPlayer ( CBasePlayer *pBlocker ) { return; }; // buz virtual void StepSound( void ); virtual void StopFollowing( BOOL clearSchedule, int speakSentence = TRUE ) {} // buz inline void Remember( int iMemory ) { m_afMemory |= iMemory; } inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } BOOL ExitScriptedSequence( ); BOOL CineCleanup( ); void StartPatrol( CBaseEntity *path ); CBaseEntity* DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng );// drop an item. //LRC float CalcRatio( CBaseEntity *pLocus ) { /*ALERT(at_console, "monster CR: %f/%f = %f\n", pev->health, pev->max_health, pev->health / pev->max_health);*/ return pev->health / pev->max_health; } void AddFacingTarget( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp ); void AddFacingTarget( const Vector &vecPosition, float flImportance, float flDuration, float flRamp ); void AddFacingTarget( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp ); float GetFacingDirection( Vector &vecDir ); CMonsterTarget m_facingQueue; Vector m_vecFacingDir; Vector m_vecDirection; // buz: rush vars string_t m_hRushEntity; int m_iRushMovetype; float m_flRushDistance; float m_flRushNextTime; }; #endif // BASEMONSTER_H