2022-12-17 13:32:43 +01:00
/***
2013-08-30 13:34:05 -07:00
*
* Copyright ( c ) 1996 - 2001 , 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 .
*
* * * */
//=========================================================
// barnacle - stationary ceiling mounted 'fishing' monster
//=========================================================
2021-11-28 16:54:48 +01:00
# include "extdll.h"
# include "util.h"
# include "cbase.h"
# include "monsters.h"
# include "schedule.h"
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
# define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is.
# define BARNACLE_PULL_SPEED 8
# define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them.
2013-08-30 13:34:05 -07:00
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
2021-11-28 16:54:48 +01:00
# define BARNACLE_AE_PUKEGIB 2
2013-08-30 13:34:05 -07:00
class CBarnacle : public CBaseMonster
{
public :
2021-03-05 23:07:22 +01:00
void Spawn ( ) override ;
void Precache ( ) override ;
2021-11-28 16:54:48 +01:00
CBaseEntity * TongueTouchEnt ( float * pflLength ) ;
int Classify ( ) override ;
void HandleAnimEvent ( MonsterEvent_t * pEvent ) override ;
void EXPORT BarnacleThink ( ) ;
void EXPORT WaitTillDead ( ) ;
void Killed ( entvars_t * pevAttacker , int iGib ) override ;
bool TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType ) override ;
bool Save ( CSave & save ) override ;
bool Restore ( CRestore & restore ) override ;
static TYPEDESCRIPTION m_SaveData [ ] ;
2013-08-30 13:34:05 -07:00
float m_flAltitude ;
float m_flKillVictimTime ;
2021-11-28 16:54:48 +01:00
int m_cGibs ; // barnacle loads up on gibs each time it kills something.
bool m_fTongueExtended ;
bool m_fLiftingPrey ;
2013-08-30 13:34:05 -07:00
float m_flTongueAdj ;
} ;
2021-11-28 16:54:48 +01:00
LINK_ENTITY_TO_CLASS ( monster_barnacle , CBarnacle ) ;
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
TYPEDESCRIPTION CBarnacle : : m_SaveData [ ] =
{
DEFINE_FIELD ( CBarnacle , m_flAltitude , FIELD_FLOAT ) ,
DEFINE_FIELD ( CBarnacle , m_flKillVictimTime , FIELD_TIME ) ,
DEFINE_FIELD ( CBarnacle , m_cGibs , FIELD_INTEGER ) , // barnacle loads up on gibs each time it kills something.
DEFINE_FIELD ( CBarnacle , m_fTongueExtended , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( CBarnacle , m_fLiftingPrey , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( CBarnacle , m_flTongueAdj , FIELD_FLOAT ) ,
2013-08-30 13:34:05 -07:00
} ;
2021-11-28 16:54:48 +01:00
IMPLEMENT_SAVERESTORE ( CBarnacle , CBaseMonster ) ;
2013-08-30 13:34:05 -07:00
//=========================================================
2021-11-28 16:54:48 +01:00
// Classify - indicates this monster's place in the
2013-08-30 13:34:05 -07:00
// relationship table.
//=========================================================
2021-11-29 20:31:17 +01:00
int CBarnacle : : Classify ( )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
return CLASS_ALIEN_MONSTER ;
2013-08-30 13:34:05 -07:00
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
2021-11-29 20:31:17 +01:00
void CBarnacle : : HandleAnimEvent ( MonsterEvent_t * pEvent )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
switch ( pEvent - > event )
2013-08-30 13:34:05 -07:00
{
case BARNACLE_AE_PUKEGIB :
2021-11-28 16:54:48 +01:00
CGib : : SpawnRandomGibs ( pev , 1 , true ) ;
2013-08-30 13:34:05 -07:00
break ;
default :
2021-11-28 16:54:48 +01:00
CBaseMonster : : HandleAnimEvent ( pEvent ) ;
2013-08-30 13:34:05 -07:00
break ;
}
}
//=========================================================
// Spawn
//=========================================================
2021-11-29 20:31:17 +01:00
void CBarnacle : : Spawn ( )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
Precache ( ) ;
2013-08-30 13:34:05 -07:00
SET_MODEL ( ENT ( pev ) , " models/barnacle.mdl " ) ;
2021-11-28 16:54:48 +01:00
UTIL_SetSize ( pev , Vector ( - 16 , - 16 , - 32 ) , Vector ( 16 , 16 , 0 ) ) ;
pev - > solid = SOLID_SLIDEBOX ;
pev - > movetype = MOVETYPE_NONE ;
pev - > takedamage = DAMAGE_AIM ;
m_bloodColor = BLOOD_COLOR_RED ;
pev - > effects = EF_INVLIGHT ; // take light from the ceiling
pev - > health = 25 ;
m_flFieldOfView = 0.5 ; // indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE ;
m_flKillVictimTime = 0 ;
m_cGibs = 0 ;
m_fLiftingPrey = false ;
m_flTongueAdj = - 100 ;
2013-08-30 13:34:05 -07:00
InitBoneControllers ( ) ;
2021-11-28 16:54:48 +01:00
SetActivity ( ACT_IDLE ) ;
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
SetThink ( & CBarnacle : : BarnacleThink ) ;
2013-08-30 13:34:05 -07:00
pev - > nextthink = gpGlobals - > time + 0.5 ;
2021-11-28 16:54:48 +01:00
UTIL_SetOrigin ( pev , pev - > origin ) ;
2013-08-30 13:34:05 -07:00
}
2021-11-28 16:54:48 +01:00
bool CBarnacle : : TakeDamage ( entvars_t * pevInflictor , entvars_t * pevAttacker , float flDamage , int bitsDamageType )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
if ( ( bitsDamageType & DMG_CLUB ) ! = 0 )
2013-08-30 13:34:05 -07:00
{
flDamage = pev - > health ;
}
2021-11-28 16:54:48 +01:00
return CBaseMonster : : TakeDamage ( pevInflictor , pevAttacker , flDamage , bitsDamageType ) ;
2013-08-30 13:34:05 -07:00
}
//=========================================================
//=========================================================
2021-11-29 20:31:17 +01:00
void CBarnacle : : BarnacleThink ( )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
CBaseEntity * pTouchEnt ;
CBaseMonster * pVictim ;
2013-08-30 13:34:05 -07:00
float flLength ;
pev - > nextthink = gpGlobals - > time + 0.1 ;
2021-11-28 16:54:48 +01:00
if ( m_hEnemy ! = NULL )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
// barnacle has prey.
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
if ( ! m_hEnemy - > IsAlive ( ) )
2013-08-30 13:34:05 -07:00
{
// someone (maybe even the barnacle) killed the prey. Reset barnacle.
2021-11-28 16:54:48 +01:00
m_fLiftingPrey = false ; // indicate that we're not lifting prey.
2013-08-30 13:34:05 -07:00
m_hEnemy = NULL ;
return ;
}
2021-11-28 16:54:48 +01:00
if ( m_fLiftingPrey )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
if ( m_hEnemy ! = NULL & & m_hEnemy - > pev - > deadflag ! = DEAD_NO )
2013-08-30 13:34:05 -07:00
{
// crap, someone killed the prey on the way up.
m_hEnemy = NULL ;
2021-11-19 13:43:33 +01:00
m_fLiftingPrey = false ;
2013-08-30 13:34:05 -07:00
return ;
}
2021-11-28 16:54:48 +01:00
// still pulling prey.
2013-08-30 13:34:05 -07:00
Vector vecNewEnemyOrigin = m_hEnemy - > pev - > origin ;
vecNewEnemyOrigin . x = pev - > origin . x ;
vecNewEnemyOrigin . y = pev - > origin . y ;
// guess as to where their neck is
2021-11-28 16:54:48 +01:00
vecNewEnemyOrigin . x - = 6 * cos ( m_hEnemy - > pev - > angles . y * M_PI / 180.0 ) ;
vecNewEnemyOrigin . y - = 6 * sin ( m_hEnemy - > pev - > angles . y * M_PI / 180.0 ) ;
2013-08-30 13:34:05 -07:00
m_flAltitude - = BARNACLE_PULL_SPEED ;
vecNewEnemyOrigin . z + = BARNACLE_PULL_SPEED ;
2021-11-28 16:54:48 +01:00
if ( fabs ( pev - > origin . z - ( vecNewEnemyOrigin . z + m_hEnemy - > pev - > view_ofs . z - 8 ) ) < BARNACLE_BODY_HEIGHT )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
// prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body )
2021-11-19 13:43:33 +01:00
m_fLiftingPrey = false ;
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_bite3.wav " , 1 , ATTN_NORM ) ;
2013-08-30 13:34:05 -07:00
pVictim = m_hEnemy - > MyMonsterPointer ( ) ;
2021-11-28 16:54:48 +01:00
m_flKillVictimTime = gpGlobals - > time + 10 ; // now that the victim is in place, the killing bite will be administered in 10 seconds.
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
if ( pVictim )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
pVictim - > BarnacleVictimBitten ( pev ) ;
SetActivity ( ACT_EAT ) ;
2013-08-30 13:34:05 -07:00
}
}
2021-11-28 16:54:48 +01:00
UTIL_SetOrigin ( m_hEnemy - > pev , vecNewEnemyOrigin ) ;
2013-08-30 13:34:05 -07:00
}
else
{
2021-11-28 16:54:48 +01:00
// prey is lifted fully into feeding position and is dangling there.
2013-08-30 13:34:05 -07:00
pVictim = m_hEnemy - > MyMonsterPointer ( ) ;
2021-11-28 16:54:48 +01:00
if ( m_flKillVictimTime ! = - 1 & & gpGlobals - > time > m_flKillVictimTime )
2013-08-30 13:34:05 -07:00
{
// kill!
2021-11-28 16:54:48 +01:00
if ( pVictim )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
pVictim - > TakeDamage ( pev , pev , pVictim - > pev - > health , DMG_SLASH | DMG_ALWAYSGIB ) ;
2013-08-30 13:34:05 -07:00
m_cGibs = 3 ;
}
return ;
}
// bite prey every once in a while
2021-11-28 16:54:48 +01:00
if ( pVictim & & ( RANDOM_LONG ( 0 , 49 ) = = 0 ) )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
switch ( RANDOM_LONG ( 0 , 2 ) )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
case 0 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_chew1.wav " , 1 , ATTN_NORM ) ;
break ;
case 1 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_chew2.wav " , 1 , ATTN_NORM ) ;
break ;
case 2 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_chew3.wav " , 1 , ATTN_NORM ) ;
break ;
2013-08-30 13:34:05 -07:00
}
2021-11-28 16:54:48 +01:00
pVictim - > BarnacleVictimBitten ( pev ) ;
2013-08-30 13:34:05 -07:00
}
}
}
else
{
2021-11-28 16:54:48 +01:00
// barnacle has no prey right now, so just idle and check to see if anything is touching the tongue.
2013-08-30 13:34:05 -07:00
// If idle and no nearby client, don't think so often
2021-11-28 16:54:48 +01:00
if ( FNullEnt ( FIND_CLIENT_IN_PVS ( edict ( ) ) ) )
pev - > nextthink = gpGlobals - > time + RANDOM_FLOAT ( 1 , 1.5 ) ; // Stagger a bit to keep barnacles from thinking on the same frame
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
if ( m_fSequenceFinished )
{ // this is done so barnacle will fidget.
SetActivity ( ACT_IDLE ) ;
2013-08-30 13:34:05 -07:00
m_flTongueAdj = - 100 ;
}
2021-11-28 16:54:48 +01:00
if ( 0 ! = m_cGibs & & RANDOM_LONG ( 0 , 99 ) = = 1 )
2013-08-30 13:34:05 -07:00
{
// cough up a gib.
2021-11-28 16:54:48 +01:00
CGib : : SpawnRandomGibs ( pev , 1 , true ) ;
2013-08-30 13:34:05 -07:00
m_cGibs - - ;
2021-11-28 16:54:48 +01:00
switch ( RANDOM_LONG ( 0 , 2 ) )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
case 0 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_chew1.wav " , 1 , ATTN_NORM ) ;
break ;
case 1 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_chew2.wav " , 1 , ATTN_NORM ) ;
break ;
case 2 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_chew3.wav " , 1 , ATTN_NORM ) ;
break ;
2013-08-30 13:34:05 -07:00
}
}
2021-11-28 16:54:48 +01:00
pTouchEnt = TongueTouchEnt ( & flLength ) ;
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
if ( pTouchEnt ! = NULL & & m_fTongueExtended )
2013-08-30 13:34:05 -07:00
{
// tongue is fully extended, and is touching someone.
2021-11-28 16:54:48 +01:00
if ( pTouchEnt - > FBecomeProne ( ) )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_alert2.wav " , 1 , ATTN_NORM ) ;
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
SetSequenceByName ( " attack1 " ) ;
2013-08-30 13:34:05 -07:00
m_flTongueAdj = - 20 ;
m_hEnemy = pTouchEnt ;
pTouchEnt - > pev - > movetype = MOVETYPE_FLY ;
pTouchEnt - > pev - > velocity = g_vecZero ;
pTouchEnt - > pev - > basevelocity = g_vecZero ;
pTouchEnt - > pev - > origin . x = pev - > origin . x ;
pTouchEnt - > pev - > origin . y = pev - > origin . y ;
2021-11-28 16:54:48 +01:00
m_fLiftingPrey = true ; // indicate that we should be lifting prey.
m_flKillVictimTime = - 1 ; // set this to a bogus time while the victim is lifted.
2013-08-30 13:34:05 -07:00
m_flAltitude = ( pev - > origin . z - pTouchEnt - > EyePosition ( ) . z ) ;
}
}
else
{
2021-11-28 16:54:48 +01:00
// calculate a new length for the tongue to be clear of anything else that moves under it.
if ( m_flAltitude < flLength )
2013-08-30 13:34:05 -07:00
{
// if tongue is higher than is should be, lower it kind of slowly.
m_flAltitude + = BARNACLE_PULL_SPEED ;
2021-11-19 13:43:33 +01:00
m_fTongueExtended = false ;
2013-08-30 13:34:05 -07:00
}
else
{
m_flAltitude = flLength ;
2021-11-19 13:45:16 +01:00
m_fTongueExtended = true ;
2013-08-30 13:34:05 -07:00
}
}
}
// ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj );
2021-11-28 16:54:48 +01:00
SetBoneController ( 0 , - ( m_flAltitude + m_flTongueAdj ) ) ;
StudioFrameAdvance ( 0.1 ) ;
2013-08-30 13:34:05 -07:00
}
//=========================================================
// Killed.
//=========================================================
2021-11-29 20:31:17 +01:00
void CBarnacle : : Killed ( entvars_t * pevAttacker , int iGib )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
CBaseMonster * pVictim ;
2013-08-30 13:34:05 -07:00
pev - > solid = SOLID_NOT ;
pev - > takedamage = DAMAGE_NO ;
2021-11-28 16:54:48 +01:00
if ( m_hEnemy ! = NULL )
2013-08-30 13:34:05 -07:00
{
pVictim = m_hEnemy - > MyMonsterPointer ( ) ;
2021-11-28 16:54:48 +01:00
if ( pVictim )
2013-08-30 13:34:05 -07:00
{
pVictim - > BarnacleVictimReleased ( ) ;
}
}
2021-11-28 16:54:48 +01:00
// CGib::SpawnRandomGibs( pev, 4, 1 );
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
switch ( RANDOM_LONG ( 0 , 1 ) )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
case 0 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_die1.wav " , 1 , ATTN_NORM ) ;
break ;
case 1 :
EMIT_SOUND ( ENT ( pev ) , CHAN_WEAPON , " barnacle/bcl_die3.wav " , 1 , ATTN_NORM ) ;
break ;
2013-08-30 13:34:05 -07:00
}
2021-11-28 16:54:48 +01:00
SetActivity ( ACT_DIESIMPLE ) ;
SetBoneController ( 0 , 0 ) ;
StudioFrameAdvance ( 0.1 ) ;
2013-08-30 13:34:05 -07:00
pev - > nextthink = gpGlobals - > time + 0.1 ;
2021-11-28 16:54:48 +01:00
SetThink ( & CBarnacle : : WaitTillDead ) ;
2013-08-30 13:34:05 -07:00
}
//=========================================================
//=========================================================
2021-11-29 20:31:17 +01:00
void CBarnacle : : WaitTillDead ( )
2013-08-30 13:34:05 -07:00
{
pev - > nextthink = gpGlobals - > time + 0.1 ;
2021-11-28 16:54:48 +01:00
float flInterval = StudioFrameAdvance ( 0.1 ) ;
DispatchAnimEvents ( flInterval ) ;
2013-08-30 13:34:05 -07:00
2021-11-28 16:54:48 +01:00
if ( m_fSequenceFinished )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
// death anim finished.
2013-08-30 13:34:05 -07:00
StopAnimation ( ) ;
2021-11-28 16:54:48 +01:00
SetThink ( NULL ) ;
2013-08-30 13:34:05 -07:00
}
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
2021-11-29 20:31:17 +01:00
void CBarnacle : : Precache ( )
2013-08-30 13:34:05 -07:00
{
PRECACHE_MODEL ( " models/barnacle.mdl " ) ;
2021-11-28 16:54:48 +01:00
PRECACHE_SOUND ( " barnacle/bcl_alert2.wav " ) ; //happy, lifting food up
PRECACHE_SOUND ( " barnacle/bcl_bite3.wav " ) ; //just got food to mouth
2013-08-30 13:34:05 -07:00
PRECACHE_SOUND ( " barnacle/bcl_chew1.wav " ) ;
PRECACHE_SOUND ( " barnacle/bcl_chew2.wav " ) ;
PRECACHE_SOUND ( " barnacle/bcl_chew3.wav " ) ;
2021-11-28 16:54:48 +01:00
PRECACHE_SOUND ( " barnacle/bcl_die1.wav " ) ;
PRECACHE_SOUND ( " barnacle/bcl_die3.wav " ) ;
}
2013-08-30 13:34:05 -07:00
//=========================================================
// TongueTouchEnt - does a trace along the barnacle's tongue
// to see if any entity is touching it. Also stores the length
// of the trace in the int pointer provided.
//=========================================================
2021-11-28 16:54:48 +01:00
# define BARNACLE_CHECK_SPACING 8
2021-11-29 20:31:17 +01:00
CBaseEntity * CBarnacle : : TongueTouchEnt ( float * pflLength )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
TraceResult tr ;
float length ;
2013-08-30 13:34:05 -07:00
// trace once to hit architecture and see if the tongue needs to change position.
2021-11-28 16:54:48 +01:00
UTIL_TraceLine ( pev - > origin , pev - > origin - Vector ( 0 , 0 , 2048 ) , ignore_monsters , ENT ( pev ) , & tr ) ;
length = fabs ( pev - > origin . z - tr . vecEndPos . z ) ;
if ( pflLength )
2013-08-30 13:34:05 -07:00
{
* pflLength = length ;
}
2021-11-28 16:54:48 +01:00
Vector delta = Vector ( BARNACLE_CHECK_SPACING , BARNACLE_CHECK_SPACING , 0 ) ;
2013-08-30 13:34:05 -07:00
Vector mins = pev - > origin - delta ;
Vector maxs = pev - > origin + delta ;
maxs . z = pev - > origin . z ;
mins . z - = length ;
2021-11-28 16:54:48 +01:00
CBaseEntity * pList [ 10 ] ;
int count = UTIL_EntitiesInBox ( pList , 10 , mins , maxs , ( FL_CLIENT | FL_MONSTER ) ) ;
if ( 0 ! = count )
2013-08-30 13:34:05 -07:00
{
2021-11-28 16:54:48 +01:00
for ( int i = 0 ; i < count ; i + + )
2013-08-30 13:34:05 -07:00
{
// only clients and monsters
2021-11-28 16:54:48 +01:00
if ( pList [ i ] ! = this & & IRelationship ( pList [ i ] ) > R_NO & & pList [ i ] - > pev - > deadflag = = DEAD_NO ) // this ent is one of our enemies. Barnacle tries to eat it.
2013-08-30 13:34:05 -07:00
{
return pList [ i ] ;
}
}
}
return NULL ;
}