You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1044 lines
25 KiB
1044 lines
25 KiB
/*** |
|
* |
|
* 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. |
|
* |
|
****/ |
|
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) |
|
|
|
/* |
|
|
|
h_tentacle.cpp - silo of death tentacle monster (half life) |
|
|
|
*/ |
|
|
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "monsters.h" |
|
#include "weapons.h" |
|
#include "soundent.h" |
|
|
|
|
|
#define ACT_T_IDLE 1010 |
|
#define ACT_T_TAP 1020 |
|
#define ACT_T_STRIKE 1030 |
|
#define ACT_T_REARIDLE 1040 |
|
|
|
class CTentacle : public CBaseMonster |
|
{ |
|
public: |
|
CTentacle( void ); |
|
|
|
void Spawn( ); |
|
void Precache( ); |
|
void KeyValue( KeyValueData *pkvd ); |
|
|
|
int Save( CSave &save ); |
|
int Restore( CRestore &restore ); |
|
static TYPEDESCRIPTION m_SaveData[]; |
|
|
|
// Don't allow the tentacle to go across transitions!!! |
|
virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } |
|
|
|
void SetObjectCollisionBox( void ) |
|
{ |
|
pev->absmin = pev->origin + Vector(-400, -400, 0); |
|
pev->absmax = pev->origin + Vector(400, 400, 850); |
|
} |
|
|
|
void EXPORT Cycle( void ); |
|
void EXPORT CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); |
|
void EXPORT Start( void ); |
|
void EXPORT DieThink( void ); |
|
|
|
void EXPORT Test( void ); |
|
|
|
void EXPORT HitTouch( CBaseEntity *pOther ); |
|
|
|
float HearingSensitivity( void ) { return 2.0; }; |
|
|
|
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); |
|
void HandleAnimEvent( MonsterEvent_t *pEvent ); |
|
void Killed( entvars_t *pevAttacker, int iGib ); |
|
|
|
MONSTERSTATE GetIdealState ( void ) { return MONSTERSTATE_IDLE; }; |
|
int CanPlaySequence( BOOL fDisregardState ) { return TRUE; }; |
|
|
|
int Classify( void ); |
|
|
|
int Level( float dz ); |
|
int MyLevel( void ); |
|
float MyHeight( void ); |
|
|
|
float m_flInitialYaw; |
|
int m_iGoalAnim; |
|
int m_iLevel; |
|
int m_iDir; |
|
float m_flFramerateAdj; |
|
float m_flSoundYaw; |
|
int m_iSoundLevel; |
|
float m_flSoundTime; |
|
float m_flSoundRadius; |
|
int m_iHitDmg; |
|
float m_flHitTime; |
|
|
|
float m_flTapRadius; |
|
|
|
float m_flNextSong; |
|
static int g_fFlySound; |
|
static int g_fSquirmSound; |
|
|
|
float m_flMaxYaw; |
|
int m_iTapSound; |
|
|
|
Vector m_vecPrevSound; |
|
float m_flPrevSoundTime; |
|
|
|
static const char *pHitSilo[]; |
|
static const char *pHitDirt[]; |
|
static const char *pHitWater[]; |
|
}; |
|
|
|
|
|
|
|
int CTentacle :: g_fFlySound; |
|
int CTentacle :: g_fSquirmSound; |
|
|
|
LINK_ENTITY_TO_CLASS( monster_tentacle, CTentacle ); |
|
|
|
// stike sounds |
|
#define TE_NONE -1 |
|
#define TE_SILO 0 |
|
#define TE_DIRT 1 |
|
#define TE_WATER 2 |
|
|
|
const char *CTentacle::pHitSilo[] = |
|
{ |
|
"tentacle/te_strike1.wav", |
|
"tentacle/te_strike2.wav", |
|
}; |
|
|
|
const char *CTentacle::pHitDirt[] = |
|
{ |
|
"player/pl_dirt1.wav", |
|
"player/pl_dirt2.wav", |
|
"player/pl_dirt3.wav", |
|
"player/pl_dirt4.wav", |
|
}; |
|
|
|
const char *CTentacle::pHitWater[] = |
|
{ |
|
"player/pl_slosh1.wav", |
|
"player/pl_slosh2.wav", |
|
"player/pl_slosh3.wav", |
|
"player/pl_slosh4.wav", |
|
}; |
|
|
|
|
|
TYPEDESCRIPTION CTentacle::m_SaveData[] = |
|
{ |
|
DEFINE_FIELD( CTentacle, m_flInitialYaw, FIELD_FLOAT ), |
|
DEFINE_FIELD( CTentacle, m_iGoalAnim, FIELD_INTEGER ), |
|
DEFINE_FIELD( CTentacle, m_iLevel, FIELD_INTEGER ), |
|
DEFINE_FIELD( CTentacle, m_iDir, FIELD_INTEGER ), |
|
DEFINE_FIELD( CTentacle, m_flFramerateAdj, FIELD_FLOAT ), |
|
DEFINE_FIELD( CTentacle, m_flSoundYaw, FIELD_FLOAT ), |
|
DEFINE_FIELD( CTentacle, m_iSoundLevel, FIELD_INTEGER ), |
|
DEFINE_FIELD( CTentacle, m_flSoundTime, FIELD_TIME ), |
|
DEFINE_FIELD( CTentacle, m_flSoundRadius, FIELD_FLOAT ), |
|
DEFINE_FIELD( CTentacle, m_iHitDmg, FIELD_INTEGER ), |
|
DEFINE_FIELD( CTentacle, m_flHitTime, FIELD_TIME ), |
|
DEFINE_FIELD( CTentacle, m_flTapRadius, FIELD_FLOAT ), |
|
DEFINE_FIELD( CTentacle, m_flNextSong, FIELD_TIME ), |
|
DEFINE_FIELD( CTentacle, m_iTapSound, FIELD_INTEGER ), |
|
DEFINE_FIELD( CTentacle, m_flMaxYaw, FIELD_FLOAT ), |
|
DEFINE_FIELD( CTentacle, m_vecPrevSound, FIELD_POSITION_VECTOR ), |
|
DEFINE_FIELD( CTentacle, m_flPrevSoundTime, FIELD_TIME ), |
|
}; |
|
IMPLEMENT_SAVERESTORE( CTentacle, CBaseMonster ); |
|
|
|
|
|
// animation sequence aliases |
|
typedef enum |
|
{ |
|
TENTACLE_ANIM_Pit_Idle, |
|
|
|
TENTACLE_ANIM_rise_to_Temp1, |
|
TENTACLE_ANIM_Temp1_to_Floor, |
|
TENTACLE_ANIM_Floor_Idle, |
|
TENTACLE_ANIM_Floor_Fidget_Pissed, |
|
TENTACLE_ANIM_Floor_Fidget_SmallRise, |
|
TENTACLE_ANIM_Floor_Fidget_Wave, |
|
TENTACLE_ANIM_Floor_Strike, |
|
TENTACLE_ANIM_Floor_Tap, |
|
TENTACLE_ANIM_Floor_Rotate, |
|
TENTACLE_ANIM_Floor_Rear, |
|
TENTACLE_ANIM_Floor_Rear_Idle, |
|
TENTACLE_ANIM_Floor_to_Lev1, |
|
|
|
TENTACLE_ANIM_Lev1_Idle, |
|
TENTACLE_ANIM_Lev1_Fidget_Claw, |
|
TENTACLE_ANIM_Lev1_Fidget_Shake, |
|
TENTACLE_ANIM_Lev1_Fidget_Snap, |
|
TENTACLE_ANIM_Lev1_Strike, |
|
TENTACLE_ANIM_Lev1_Tap, |
|
TENTACLE_ANIM_Lev1_Rotate, |
|
TENTACLE_ANIM_Lev1_Rear, |
|
TENTACLE_ANIM_Lev1_Rear_Idle, |
|
TENTACLE_ANIM_Lev1_to_Lev2, |
|
|
|
TENTACLE_ANIM_Lev2_Idle, |
|
TENTACLE_ANIM_Lev2_Fidget_Shake, |
|
TENTACLE_ANIM_Lev2_Fidget_Swing, |
|
TENTACLE_ANIM_Lev2_Fidget_Tut, |
|
TENTACLE_ANIM_Lev2_Strike, |
|
TENTACLE_ANIM_Lev2_Tap, |
|
TENTACLE_ANIM_Lev2_Rotate, |
|
TENTACLE_ANIM_Lev2_Rear, |
|
TENTACLE_ANIM_Lev2_Rear_Idle, |
|
TENTACLE_ANIM_Lev2_to_Lev3, |
|
|
|
TENTACLE_ANIM_Lev3_Idle, |
|
TENTACLE_ANIM_Lev3_Fidget_Shake, |
|
TENTACLE_ANIM_Lev3_Fidget_Side, |
|
TENTACLE_ANIM_Lev3_Fidget_Swipe, |
|
TENTACLE_ANIM_Lev3_Strike, |
|
TENTACLE_ANIM_Lev3_Tap, |
|
TENTACLE_ANIM_Lev3_Rotate, |
|
TENTACLE_ANIM_Lev3_Rear, |
|
TENTACLE_ANIM_Lev3_Rear_Idle, |
|
|
|
TENTACLE_ANIM_Lev1_Door_reach, |
|
|
|
TENTACLE_ANIM_Lev3_to_Engine, |
|
TENTACLE_ANIM_Engine_Idle, |
|
TENTACLE_ANIM_Engine_Sway, |
|
TENTACLE_ANIM_Engine_Swat, |
|
TENTACLE_ANIM_Engine_Bob, |
|
TENTACLE_ANIM_Engine_Death1, |
|
TENTACLE_ANIM_Engine_Death2, |
|
TENTACLE_ANIM_Engine_Death3, |
|
|
|
TENTACLE_ANIM_none |
|
} TENTACLE_ANIM; |
|
|
|
|
|
|
|
|
|
|
|
//========================================================= |
|
// Classify - indicates this monster's place in the |
|
// relationship table. |
|
//========================================================= |
|
int CTentacle :: Classify ( void ) |
|
{ |
|
return CLASS_ALIEN_MONSTER; |
|
} |
|
|
|
// |
|
// Tentacle Spawn |
|
// |
|
void CTentacle :: Spawn( ) |
|
{ |
|
Precache( ); |
|
|
|
pev->solid = SOLID_BBOX; |
|
pev->movetype = MOVETYPE_FLY; |
|
pev->effects = 0; |
|
pev->health = 75; |
|
pev->sequence = 0; |
|
|
|
SET_MODEL(ENT(pev), "models/tentacle2.mdl"); |
|
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) ); |
|
|
|
pev->takedamage = DAMAGE_AIM; |
|
pev->flags |= FL_MONSTER; |
|
|
|
m_bloodColor = BLOOD_COLOR_GREEN; |
|
|
|
SetThink( &Start ); |
|
SetTouch( &HitTouch ); |
|
SetUse( &CommandUse ); |
|
|
|
pev->nextthink = gpGlobals->time + 0.2; |
|
|
|
ResetSequenceInfo( ); |
|
m_iDir = 1; |
|
|
|
pev->yaw_speed = 18; |
|
m_flInitialYaw = pev->angles.y; |
|
pev->ideal_yaw = m_flInitialYaw; |
|
|
|
g_fFlySound = FALSE; |
|
g_fSquirmSound = FALSE; |
|
|
|
m_iHitDmg = 20; |
|
|
|
if (m_flMaxYaw <= 0) |
|
m_flMaxYaw = 65; |
|
|
|
m_MonsterState = MONSTERSTATE_IDLE; |
|
|
|
// SetThink( &Test ); |
|
UTIL_SetOrigin( pev, pev->origin ); |
|
} |
|
|
|
void CTentacle :: Precache( ) |
|
{ |
|
PRECACHE_MODEL("models/tentacle2.mdl"); |
|
|
|
PRECACHE_SOUND("ambience/flies.wav"); |
|
PRECACHE_SOUND("ambience/squirm2.wav"); |
|
|
|
PRECACHE_SOUND("tentacle/te_alert1.wav"); |
|
PRECACHE_SOUND("tentacle/te_alert2.wav"); |
|
PRECACHE_SOUND("tentacle/te_flies1.wav"); |
|
PRECACHE_SOUND("tentacle/te_move1.wav"); |
|
PRECACHE_SOUND("tentacle/te_move2.wav"); |
|
PRECACHE_SOUND("tentacle/te_roar1.wav"); |
|
PRECACHE_SOUND("tentacle/te_roar2.wav"); |
|
PRECACHE_SOUND("tentacle/te_search1.wav"); |
|
PRECACHE_SOUND("tentacle/te_search2.wav"); |
|
PRECACHE_SOUND("tentacle/te_sing1.wav"); |
|
PRECACHE_SOUND("tentacle/te_sing2.wav"); |
|
PRECACHE_SOUND("tentacle/te_squirm2.wav"); |
|
PRECACHE_SOUND("tentacle/te_strike1.wav"); |
|
PRECACHE_SOUND("tentacle/te_strike2.wav"); |
|
PRECACHE_SOUND("tentacle/te_swing1.wav"); |
|
PRECACHE_SOUND("tentacle/te_swing2.wav"); |
|
|
|
PRECACHE_SOUND_ARRAY( pHitSilo ); |
|
PRECACHE_SOUND_ARRAY( pHitDirt ); |
|
PRECACHE_SOUND_ARRAY( pHitWater ); |
|
} |
|
|
|
|
|
CTentacle::CTentacle( ) |
|
{ |
|
m_flMaxYaw = 65; |
|
m_iTapSound = 0; |
|
} |
|
|
|
void CTentacle::KeyValue( KeyValueData *pkvd ) |
|
{ |
|
if (FStrEq(pkvd->szKeyName, "sweeparc")) |
|
{ |
|
m_flMaxYaw = atof(pkvd->szValue) / 2.0; |
|
pkvd->fHandled = TRUE; |
|
} |
|
else if (FStrEq(pkvd->szKeyName, "sound")) |
|
{ |
|
m_iTapSound = atoi(pkvd->szValue); |
|
pkvd->fHandled = TRUE; |
|
|
|
} |
|
else |
|
CBaseMonster::KeyValue( pkvd ); |
|
} |
|
|
|
|
|
|
|
int CTentacle :: Level( float dz ) |
|
{ |
|
if (dz < 216) |
|
return 0; |
|
if (dz < 408) |
|
return 1; |
|
if (dz < 600) |
|
return 2; |
|
return 3; |
|
} |
|
|
|
|
|
float CTentacle :: MyHeight( ) |
|
{ |
|
switch ( MyLevel( ) ) |
|
{ |
|
case 1: |
|
return 256; |
|
case 2: |
|
return 448; |
|
case 3: |
|
return 640; |
|
} |
|
return 0; |
|
} |
|
|
|
|
|
int CTentacle :: MyLevel( ) |
|
{ |
|
switch( pev->sequence ) |
|
{ |
|
case TENTACLE_ANIM_Pit_Idle: |
|
return -1; |
|
|
|
case TENTACLE_ANIM_rise_to_Temp1: |
|
case TENTACLE_ANIM_Temp1_to_Floor: |
|
case TENTACLE_ANIM_Floor_to_Lev1: |
|
return 0; |
|
|
|
case TENTACLE_ANIM_Floor_Idle: |
|
case TENTACLE_ANIM_Floor_Fidget_Pissed: |
|
case TENTACLE_ANIM_Floor_Fidget_SmallRise: |
|
case TENTACLE_ANIM_Floor_Fidget_Wave: |
|
case TENTACLE_ANIM_Floor_Strike: |
|
case TENTACLE_ANIM_Floor_Tap: |
|
case TENTACLE_ANIM_Floor_Rotate: |
|
case TENTACLE_ANIM_Floor_Rear: |
|
case TENTACLE_ANIM_Floor_Rear_Idle: |
|
return 0; |
|
|
|
case TENTACLE_ANIM_Lev1_Idle: |
|
case TENTACLE_ANIM_Lev1_Fidget_Claw: |
|
case TENTACLE_ANIM_Lev1_Fidget_Shake: |
|
case TENTACLE_ANIM_Lev1_Fidget_Snap: |
|
case TENTACLE_ANIM_Lev1_Strike: |
|
case TENTACLE_ANIM_Lev1_Tap: |
|
case TENTACLE_ANIM_Lev1_Rotate: |
|
case TENTACLE_ANIM_Lev1_Rear: |
|
case TENTACLE_ANIM_Lev1_Rear_Idle: |
|
return 1; |
|
|
|
case TENTACLE_ANIM_Lev1_to_Lev2: |
|
return 1; |
|
|
|
case TENTACLE_ANIM_Lev2_Idle: |
|
case TENTACLE_ANIM_Lev2_Fidget_Shake: |
|
case TENTACLE_ANIM_Lev2_Fidget_Swing: |
|
case TENTACLE_ANIM_Lev2_Fidget_Tut: |
|
case TENTACLE_ANIM_Lev2_Strike: |
|
case TENTACLE_ANIM_Lev2_Tap: |
|
case TENTACLE_ANIM_Lev2_Rotate: |
|
case TENTACLE_ANIM_Lev2_Rear: |
|
case TENTACLE_ANIM_Lev2_Rear_Idle: |
|
return 2; |
|
|
|
case TENTACLE_ANIM_Lev2_to_Lev3: |
|
return 2; |
|
|
|
case TENTACLE_ANIM_Lev3_Idle: |
|
case TENTACLE_ANIM_Lev3_Fidget_Shake: |
|
case TENTACLE_ANIM_Lev3_Fidget_Side: |
|
case TENTACLE_ANIM_Lev3_Fidget_Swipe: |
|
case TENTACLE_ANIM_Lev3_Strike: |
|
case TENTACLE_ANIM_Lev3_Tap: |
|
case TENTACLE_ANIM_Lev3_Rotate: |
|
case TENTACLE_ANIM_Lev3_Rear: |
|
case TENTACLE_ANIM_Lev3_Rear_Idle: |
|
return 3; |
|
|
|
case TENTACLE_ANIM_Lev1_Door_reach: |
|
return -1; |
|
} |
|
return -1; |
|
} |
|
|
|
|
|
void CTentacle :: Test( void ) |
|
{ |
|
pev->sequence = TENTACLE_ANIM_Floor_Strike; |
|
pev->framerate = 0; |
|
StudioFrameAdvance( ); |
|
pev->nextthink = gpGlobals->time + 0.1; |
|
} |
|
|
|
|
|
|
|
// |
|
// TentacleThink |
|
// |
|
void CTentacle :: Cycle( void ) |
|
{ |
|
// ALERT( at_console, "%s %.2f %d %d\n", STRING( pev->targetname ), pev->origin.z, m_MonsterState, m_IdealMonsterState ); |
|
pev->nextthink = gpGlobals-> time + 0.1; |
|
|
|
// ALERT( at_console, "%s %d %d %d %f %f\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim, m_iDir, pev->framerate, pev->health ); |
|
|
|
if (m_MonsterState == MONSTERSTATE_SCRIPT || m_IdealMonsterState == MONSTERSTATE_SCRIPT) |
|
{ |
|
pev->angles.y = m_flInitialYaw; |
|
pev->ideal_yaw = m_flInitialYaw; |
|
ClearConditions( IgnoreConditions() ); |
|
MonsterThink( ); |
|
m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; |
|
return; |
|
} |
|
|
|
DispatchAnimEvents( ); |
|
StudioFrameAdvance( ); |
|
|
|
ChangeYaw( pev->yaw_speed ); |
|
|
|
CSound *pSound; |
|
|
|
Listen( ); |
|
|
|
// Listen will set this if there's something in my sound list |
|
if ( HasConditions( bits_COND_HEAR_SOUND ) ) |
|
pSound = PBestSound(); |
|
else |
|
pSound = NULL; |
|
|
|
if ( pSound ) |
|
{ |
|
Vector vecDir; |
|
if (gpGlobals->time - m_flPrevSoundTime < 0.5) |
|
{ |
|
float dt = gpGlobals->time - m_flPrevSoundTime; |
|
vecDir = pSound->m_vecOrigin + (pSound->m_vecOrigin - m_vecPrevSound) / dt - pev->origin; |
|
} |
|
else |
|
{ |
|
vecDir = pSound->m_vecOrigin - pev->origin; |
|
} |
|
m_flPrevSoundTime = gpGlobals->time; |
|
m_vecPrevSound = pSound->m_vecOrigin; |
|
|
|
m_flSoundYaw = UTIL_VecToYaw ( vecDir ) - m_flInitialYaw; |
|
m_iSoundLevel = Level( vecDir.z ); |
|
|
|
if (m_flSoundYaw < -180) |
|
m_flSoundYaw += 360; |
|
if (m_flSoundYaw > 180) |
|
m_flSoundYaw -= 360; |
|
|
|
// ALERT( at_console, "sound %d %.0f\n", m_iSoundLevel, m_flSoundYaw ); |
|
if (m_flSoundTime < gpGlobals->time) |
|
{ |
|
// play "I hear new something" sound |
|
char *sound; |
|
|
|
switch( RANDOM_LONG(0,1) ) |
|
{ |
|
case 0: sound = "tentacle/te_alert1.wav"; break; |
|
case 1: sound = "tentacle/te_alert2.wav"; break; |
|
} |
|
|
|
// UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); |
|
} |
|
m_flSoundTime = gpGlobals->time + RANDOM_FLOAT( 5.0, 10.0 ); |
|
} |
|
|
|
// clip ideal_yaw |
|
float dy = m_flSoundYaw; |
|
switch( pev->sequence ) |
|
{ |
|
case TENTACLE_ANIM_Floor_Rear: |
|
case TENTACLE_ANIM_Floor_Rear_Idle: |
|
case TENTACLE_ANIM_Lev1_Rear: |
|
case TENTACLE_ANIM_Lev1_Rear_Idle: |
|
case TENTACLE_ANIM_Lev2_Rear: |
|
case TENTACLE_ANIM_Lev2_Rear_Idle: |
|
case TENTACLE_ANIM_Lev3_Rear: |
|
case TENTACLE_ANIM_Lev3_Rear_Idle: |
|
if (dy < 0 && dy > -m_flMaxYaw) |
|
dy = -m_flMaxYaw; |
|
if (dy > 0 && dy < m_flMaxYaw) |
|
dy = m_flMaxYaw; |
|
break; |
|
default: |
|
if (dy < -m_flMaxYaw) |
|
dy = -m_flMaxYaw; |
|
if (dy > m_flMaxYaw) |
|
dy = m_flMaxYaw; |
|
} |
|
pev->ideal_yaw = m_flInitialYaw + dy; |
|
|
|
if (m_fSequenceFinished) |
|
{ |
|
// ALERT( at_console, "%s done %d %d\n", STRING( pev->targetname ), pev->sequence, m_iGoalAnim ); |
|
if (pev->health <= 1) |
|
{ |
|
m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; |
|
if (pev->sequence == TENTACLE_ANIM_Pit_Idle) |
|
{ |
|
pev->health = 75; |
|
} |
|
} |
|
else if ( m_flSoundTime > gpGlobals->time ) |
|
{ |
|
if (m_flSoundYaw >= -(m_flMaxYaw + 30) && m_flSoundYaw <= (m_flMaxYaw + 30)) |
|
{ |
|
// strike |
|
m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); |
|
} |
|
else if (m_flSoundYaw >= -m_flMaxYaw * 2 && m_flSoundYaw <= m_flMaxYaw * 2) |
|
{ |
|
// tap |
|
m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); |
|
} |
|
else |
|
{ |
|
// go into rear idle |
|
m_iGoalAnim = LookupActivity( ACT_T_REARIDLE + m_iSoundLevel ); |
|
} |
|
} |
|
else if (pev->sequence == TENTACLE_ANIM_Pit_Idle) |
|
{ |
|
// stay in pit until hear noise |
|
m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; |
|
} |
|
else if (pev->sequence == m_iGoalAnim) |
|
{ |
|
if (MyLevel() >= 0 && gpGlobals->time < m_flSoundTime) |
|
{ |
|
if (RANDOM_LONG(0,9) < m_flSoundTime - gpGlobals->time) |
|
{ |
|
// continue stike |
|
m_iGoalAnim = LookupActivity( ACT_T_STRIKE + m_iSoundLevel ); |
|
} |
|
else |
|
{ |
|
// tap |
|
m_iGoalAnim = LookupActivity( ACT_T_TAP + m_iSoundLevel ); |
|
} |
|
} |
|
else if (MyLevel( ) < 0) |
|
{ |
|
m_iGoalAnim = LookupActivity( ACT_T_IDLE + 0 ); |
|
} |
|
else |
|
{ |
|
if (m_flNextSong < gpGlobals->time) |
|
{ |
|
// play "I hear new something" sound |
|
char *sound; |
|
|
|
switch( RANDOM_LONG(0,1) ) |
|
{ |
|
case 0: sound = "tentacle/te_sing1.wav"; break; |
|
case 1: sound = "tentacle/te_sing2.wav"; break; |
|
} |
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, sound, 1.0, ATTN_NORM); |
|
|
|
m_flNextSong = gpGlobals->time + RANDOM_FLOAT( 10, 20 ); |
|
} |
|
|
|
if (RANDOM_LONG(0,15) == 0) |
|
{ |
|
// idle on new level |
|
m_iGoalAnim = LookupActivity( ACT_T_IDLE + RANDOM_LONG(0,3) ); |
|
} |
|
else if (RANDOM_LONG(0,3) == 0) |
|
{ |
|
// tap |
|
m_iGoalAnim = LookupActivity( ACT_T_TAP + MyLevel( ) ); |
|
} |
|
else |
|
{ |
|
// idle |
|
m_iGoalAnim = LookupActivity( ACT_T_IDLE + MyLevel( ) ); |
|
} |
|
} |
|
if (m_flSoundYaw < 0) |
|
m_flSoundYaw += RANDOM_FLOAT( 2, 8 ); |
|
else |
|
m_flSoundYaw -= RANDOM_FLOAT( 2, 8 ); |
|
} |
|
|
|
pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); |
|
|
|
if (m_iDir > 0) |
|
{ |
|
pev->frame = 0; |
|
} |
|
else |
|
{ |
|
m_iDir = -1; // just to safe |
|
pev->frame = 255; |
|
} |
|
ResetSequenceInfo( ); |
|
|
|
m_flFramerateAdj = RANDOM_FLOAT( -0.2, 0.2 ); |
|
pev->framerate = m_iDir * 1.0 + m_flFramerateAdj; |
|
|
|
switch( pev->sequence) |
|
{ |
|
case TENTACLE_ANIM_Floor_Tap: |
|
case TENTACLE_ANIM_Lev1_Tap: |
|
case TENTACLE_ANIM_Lev2_Tap: |
|
case TENTACLE_ANIM_Lev3_Tap: |
|
{ |
|
Vector vecSrc; |
|
UTIL_MakeVectors( pev->angles ); |
|
|
|
TraceResult tr1, tr2; |
|
|
|
vecSrc = pev->origin + Vector( 0, 0, MyHeight() - 4); |
|
UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr1 ); |
|
|
|
vecSrc = pev->origin + Vector( 0, 0, MyHeight() + 8); |
|
UTIL_TraceLine( vecSrc, vecSrc + gpGlobals->v_forward * 512, ignore_monsters, ENT( pev ), &tr2 ); |
|
|
|
// ALERT( at_console, "%f %f\n", tr1.flFraction * 512, tr2.flFraction * 512 ); |
|
|
|
m_flTapRadius = SetBlending( 0, RANDOM_FLOAT( tr1.flFraction * 512, tr2.flFraction * 512 ) ); |
|
} |
|
break; |
|
default: |
|
m_flTapRadius = 336; // 400 - 64 |
|
break; |
|
} |
|
pev->view_ofs.z = MyHeight( ); |
|
// ALERT( at_console, "seq %d\n", pev->sequence ); |
|
} |
|
|
|
if (m_flPrevSoundTime + 2.0 > gpGlobals->time) |
|
{ |
|
// 1.5 normal speed if hears sounds |
|
pev->framerate = m_iDir * 1.5 + m_flFramerateAdj; |
|
} |
|
else if (m_flPrevSoundTime + 5.0 > gpGlobals->time) |
|
{ |
|
// slowdown to normal |
|
pev->framerate = m_iDir + m_iDir * (5 - (gpGlobals->time - m_flPrevSoundTime)) / 2 + m_flFramerateAdj; |
|
} |
|
} |
|
|
|
|
|
|
|
void CTentacle::CommandUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
{ |
|
// ALERT( at_console, "%s triggered %d\n", STRING( pev->targetname ), useType ); |
|
switch( useType ) |
|
{ |
|
case USE_OFF: |
|
pev->takedamage = DAMAGE_NO; |
|
SetThink( &DieThink ); |
|
m_iGoalAnim = TENTACLE_ANIM_Engine_Death1; |
|
break; |
|
case USE_ON: |
|
if (pActivator) |
|
{ |
|
// ALERT( at_console, "insert sound\n"); |
|
CSoundEnt::InsertSound ( bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0 ); |
|
} |
|
break; |
|
case USE_SET: |
|
break; |
|
case USE_TOGGLE: |
|
pev->takedamage = DAMAGE_NO; |
|
SetThink( &DieThink ); |
|
m_iGoalAnim = TENTACLE_ANIM_Engine_Idle; |
|
break; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void CTentacle :: DieThink( void ) |
|
{ |
|
pev->nextthink = gpGlobals-> time + 0.1; |
|
|
|
DispatchAnimEvents( ); |
|
StudioFrameAdvance( ); |
|
|
|
ChangeYaw( 24 ); |
|
|
|
if (m_fSequenceFinished) |
|
{ |
|
if (pev->sequence == m_iGoalAnim) |
|
{ |
|
switch( m_iGoalAnim ) |
|
{ |
|
case TENTACLE_ANIM_Engine_Idle: |
|
case TENTACLE_ANIM_Engine_Sway: |
|
case TENTACLE_ANIM_Engine_Swat: |
|
case TENTACLE_ANIM_Engine_Bob: |
|
m_iGoalAnim = TENTACLE_ANIM_Engine_Sway + RANDOM_LONG( 0, 2 ); |
|
break; |
|
case TENTACLE_ANIM_Engine_Death1: |
|
case TENTACLE_ANIM_Engine_Death2: |
|
case TENTACLE_ANIM_Engine_Death3: |
|
UTIL_Remove( this ); |
|
return; |
|
} |
|
} |
|
|
|
// ALERT( at_console, "%d : %d => ", pev->sequence, m_iGoalAnim ); |
|
pev->sequence = FindTransition( pev->sequence, m_iGoalAnim, &m_iDir ); |
|
// ALERT( at_console, "%d\n", pev->sequence ); |
|
|
|
if (m_iDir > 0) |
|
{ |
|
pev->frame = 0; |
|
} |
|
else |
|
{ |
|
pev->frame = 255; |
|
} |
|
ResetSequenceInfo( ); |
|
|
|
float dy; |
|
switch( pev->sequence ) |
|
{ |
|
case TENTACLE_ANIM_Floor_Rear: |
|
case TENTACLE_ANIM_Floor_Rear_Idle: |
|
case TENTACLE_ANIM_Lev1_Rear: |
|
case TENTACLE_ANIM_Lev1_Rear_Idle: |
|
case TENTACLE_ANIM_Lev2_Rear: |
|
case TENTACLE_ANIM_Lev2_Rear_Idle: |
|
case TENTACLE_ANIM_Lev3_Rear: |
|
case TENTACLE_ANIM_Lev3_Rear_Idle: |
|
case TENTACLE_ANIM_Engine_Idle: |
|
case TENTACLE_ANIM_Engine_Sway: |
|
case TENTACLE_ANIM_Engine_Swat: |
|
case TENTACLE_ANIM_Engine_Bob: |
|
case TENTACLE_ANIM_Engine_Death1: |
|
case TENTACLE_ANIM_Engine_Death2: |
|
case TENTACLE_ANIM_Engine_Death3: |
|
pev->framerate = RANDOM_FLOAT( m_iDir - 0.2, m_iDir + 0.2 ); |
|
dy = 180; |
|
break; |
|
default: |
|
pev->framerate = 1.5; |
|
dy = 0; |
|
break; |
|
} |
|
pev->ideal_yaw = m_flInitialYaw + dy; |
|
} |
|
} |
|
|
|
|
|
void CTentacle :: HandleAnimEvent( MonsterEvent_t *pEvent ) |
|
{ |
|
char *sound; |
|
|
|
switch( pEvent->event ) |
|
{ |
|
case 1: // bang |
|
{ |
|
Vector vecSrc, vecAngles; |
|
GetAttachment( 0, vecSrc, vecAngles ); |
|
|
|
// Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (3.14192653 / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); |
|
|
|
// vecSrc.z += MyHeight( ); |
|
|
|
switch( m_iTapSound ) |
|
{ |
|
case TE_SILO: |
|
UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
case TE_NONE: |
|
break; |
|
case TE_DIRT: |
|
UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
case TE_WATER: |
|
UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
} |
|
gpGlobals->force_retouch++; |
|
} |
|
break; |
|
|
|
case 3: // start killing swing |
|
m_iHitDmg = 200; |
|
// UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing1.wav", 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
|
|
case 4: // end killing swing |
|
m_iHitDmg = 25; |
|
break; |
|
|
|
case 5: // just "whoosh" sound |
|
// UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), "tentacle/te_swing2.wav", 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
|
|
case 2: // tap scrape |
|
case 6: // light tap |
|
{ |
|
Vector vecSrc = pev->origin + m_flTapRadius * Vector( cos( pev->angles.y * (M_PI / 180.0) ), sin( pev->angles.y * (M_PI / 180.0) ), 0.0 ); |
|
|
|
vecSrc.z += MyHeight( ); |
|
|
|
float flVol = RANDOM_FLOAT( 0.3, 0.5 ); |
|
|
|
switch( m_iTapSound ) |
|
{ |
|
case TE_SILO: |
|
UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitSilo ), flVol, ATTN_NORM, 0, 100); |
|
break; |
|
case TE_NONE: |
|
break; |
|
case TE_DIRT: |
|
UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitDirt ), flVol, ATTN_NORM, 0, 100); |
|
break; |
|
case TE_WATER: |
|
UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY( pHitWater ), flVol, ATTN_NORM, 0, 100); |
|
break; |
|
} |
|
} |
|
break; |
|
|
|
|
|
case 7: // roar |
|
switch( RANDOM_LONG(0,1) ) |
|
{ |
|
case 0: sound = "tentacle/te_roar1.wav"; break; |
|
case 1: sound = "tentacle/te_roar2.wav"; break; |
|
} |
|
|
|
UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
|
|
case 8: // search |
|
switch( RANDOM_LONG(0,1) ) |
|
{ |
|
case 0: sound = "tentacle/te_search1.wav"; break; |
|
case 1: sound = "tentacle/te_search2.wav"; break; |
|
} |
|
|
|
UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
|
|
case 9: // swing |
|
switch( RANDOM_LONG(0,1) ) |
|
{ |
|
case 0: sound = "tentacle/te_move1.wav"; break; |
|
case 1: sound = "tentacle/te_move2.wav"; break; |
|
} |
|
|
|
UTIL_EmitAmbientSound(ENT(pev), pev->origin + Vector( 0, 0, MyHeight()), sound, 1.0, ATTN_NORM, 0, 100); |
|
break; |
|
|
|
default: |
|
CBaseMonster::HandleAnimEvent( pEvent ); |
|
} |
|
} |
|
|
|
|
|
// |
|
// TentacleStart |
|
// |
|
// void CTentacle :: Start( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) |
|
void CTentacle :: Start( void ) |
|
{ |
|
SetThink( &Cycle ); |
|
|
|
if ( !g_fFlySound ) |
|
{ |
|
EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/flies.wav", 1, ATTN_NORM ); |
|
g_fFlySound = TRUE; |
|
// pev->nextthink = gpGlobals-> time + 0.1; |
|
} |
|
else if ( !g_fSquirmSound ) |
|
{ |
|
EMIT_SOUND (ENT(pev), CHAN_BODY, "ambience/squirm2.wav", 1, ATTN_NORM ); |
|
g_fSquirmSound = TRUE; |
|
} |
|
|
|
pev->nextthink = gpGlobals->time + 0.1; |
|
} |
|
|
|
|
|
|
|
|
|
void CTentacle :: HitTouch( CBaseEntity *pOther ) |
|
{ |
|
TraceResult tr = UTIL_GetGlobalTrace( ); |
|
|
|
if (pOther->pev->modelindex == pev->modelindex) |
|
return; |
|
|
|
if (m_flHitTime > gpGlobals->time) |
|
return; |
|
|
|
// only look at the ones where the player hit me |
|
if (tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex) |
|
return; |
|
|
|
if (tr.iHitgroup >= 3) |
|
{ |
|
pOther->TakeDamage( pev, pev, m_iHitDmg, DMG_CRUSH ); |
|
// ALERT( at_console, "wack %3d : ", m_iHitDmg ); |
|
} |
|
else if (tr.iHitgroup != 0) |
|
{ |
|
pOther->TakeDamage( pev, pev, 20, DMG_CRUSH ); |
|
// ALERT( at_console, "tap %3d : ", 20 ); |
|
} |
|
else |
|
{ |
|
return; // Huh? |
|
} |
|
|
|
m_flHitTime = gpGlobals->time + 0.5; |
|
|
|
// ALERT( at_console, "%s : ", STRING( tr.pHit->v.classname ) ); |
|
|
|
// ALERT( at_console, "%.0f : %s : %d\n", pev->angles.y, STRING( pOther->pev->classname ), tr.iHitgroup ); |
|
} |
|
|
|
|
|
int CTentacle::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) |
|
{ |
|
if (flDamage > pev->health) |
|
{ |
|
pev->health = 1; |
|
} |
|
else |
|
{ |
|
pev->health -= flDamage; |
|
} |
|
return 1; |
|
} |
|
|
|
|
|
|
|
|
|
void CTentacle :: Killed( entvars_t *pevAttacker, int iGib ) |
|
{ |
|
m_iGoalAnim = TENTACLE_ANIM_Pit_Idle; |
|
return; |
|
} |
|
|
|
|
|
|
|
class CTentacleMaw : public CBaseMonster |
|
{ |
|
public: |
|
void Spawn( ); |
|
void Precache( ); |
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CTentacleMaw ); |
|
|
|
// |
|
// Tentacle Spawn |
|
// |
|
void CTentacleMaw :: Spawn( ) |
|
{ |
|
Precache( ); |
|
SET_MODEL(ENT(pev), "models/maw.mdl"); |
|
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); |
|
|
|
pev->solid = SOLID_NOT; |
|
pev->movetype = MOVETYPE_STEP; |
|
pev->effects = 0; |
|
pev->health = 75; |
|
pev->yaw_speed = 8; |
|
pev->sequence = 0; |
|
|
|
pev->angles.x = 90; |
|
// ResetSequenceInfo( ); |
|
} |
|
|
|
void CTentacleMaw :: Precache( ) |
|
{ |
|
PRECACHE_MODEL("models/maw.mdl"); |
|
} |
|
|
|
#endif |