diff --git a/dlls/gearbox/pitworm.cpp b/dlls/gearbox/pitworm.cpp index 135e3ea0..2ab39304 100644 --- a/dlls/gearbox/pitworm.cpp +++ b/dlls/gearbox/pitworm.cpp @@ -1,17 +1,24 @@ /*** * -* Copyright (c) 1996-2001, Valve LLC. All rights reserved. +* SPIRIT OF HALF-LIFE 1.9: OPPOSING-FORCE EDITION * -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. +* Spirit of Half-Life and their logos are the property of their respective owners. +* Copyright (c) 1996-2002, Valve LLC. 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. +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * -****/ +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +* All Rights Reserved. +* +* Base Source-Code written by Marc-Antoine Lortie (https://github.com/malortie). +* Modifications by Hammermaps.de DEV Team (support@hammermaps.de). +* +***/ #include "extdll.h" #include "util.h" @@ -22,144 +29,133 @@ #include "soundent.h" #include "weapons.h" #include "player.h" +#include "decals.h" +#define PITWORM_ATTN 0.1 #define NUM_PITWORM_LEVELS 4 class CPitWorm : public CBaseMonster { public: - void Spawn(void); - void Precache(void); - int Classify(void); - virtual int ObjectCaps(void) { return CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + void Spawn(void); + void Precache(void); + int Classify(void) { return CLASS_ALIEN_MONSTER; } + virtual int ObjectCaps(void) { return CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + void SetObjectCollisionBox() + { + pev->absmin = pev->origin + Vector( -400, -400, 0 ); + pev->absmax = pev->origin + Vector( 400, 400, 850 ); + } + BOOL FVisible(CBaseEntity* pEntity); + BOOL FVisible(const Vector& vecOrigin); - void IdleSound(void); - void AlertSound(void); - void DeathSound(void); + void IdleSound(void); + void AlertSound(void); + void DeathSound(void); + void PainSound(void); - int Save(CSave &save); - int Restore(CRestore &restore); - static TYPEDESCRIPTION m_SaveData[]; + int Save(CSave &save); + int Restore(CRestore &restore); + static TYPEDESCRIPTION m_SaveData[]; - void AngrySound(void); - void FlinchSound(void); - void SwipeSound(void); - void BeamSound(void); - void pPainSound(void); + void AngrySound(void); + void SwipeSound(void); + void BeamSound(void); - void SetObjectCollisionBox(void); - void HandleAnimEvent(MonsterEvent_t *pEvent); - int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); - void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - int CanPlaySequence(BOOL fDisregardState); - void Activate(); + void HandleAnimEvent(MonsterEvent_t *pEvent); + int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); - void EXPORT StartupThink(void); - void EXPORT DyingThink(void); - void EXPORT StartupUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); - void EXPORT NullThink(void); - void EXPORT CommandUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); - void EXPORT HuntThink(void); + void EXPORT StartupThink(void); + void EXPORT DyingThink(void); + void EXPORT StartupUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + void EXPORT NullThink(void); + void EXPORT CommandUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); + void EXPORT HuntThink(void); + void EXPORT HitTouch(CBaseEntity* pOther); - void EXPORT WormTouch(CBaseEntity* pOther); + void LockTopLevel(); + BOOL ClawAttack(); + void ShootBeam(); + void StrafeBeam(); + void ChangeLevel(); + void TrackEnemy(); - void FloatSequence(void); - void NextActivity(void); + void NextActivity(void); - Vector m_avelocity; + void EyeLight(const Vector& vecEyePos); + void BeamEffect(TraceResult& tr); - Vector m_vecTarget; - Vector m_posTarget; + int SizeForGrapple() { return GRAPPLE_LARGE; } - Vector m_vecDesired; - Vector m_posDesired; + // + float m_flNextPainSound; - Vector m_vecEmemyPos; + Vector m_vecTarget; + Vector m_posTarget; + Vector m_vecDesired; + Vector m_posDesired; - float m_flMinZ; - float m_flMaxZ; + float m_offsetBeam; + Vector m_posBeam; + Vector m_vecBeam; + Vector m_angleBeam; + float m_flBeamExpireTime; + float m_flBeamDir; - float m_flLastSeen; - float m_flPrevSeen; + float m_flTorsoYaw; + float m_flHeadYaw; + float m_flHeadPitch; + float m_flIdealTorsoYaw; + float m_flIdealHeadYaw; + float m_flIdealHeadPitch; - int m_iLevel; - int m_iClass; - float m_flAdj; - float m_distDesired; - float m_flNextBlink; + float m_flLevels[NUM_PITWORM_LEVELS]; + float m_flTargetLevels[NUM_PITWORM_LEVELS]; - int Level(float dz); + float m_flLastSeen; - const Vector& IdealPosition(const int level) const; - const Vector& IdealPosition(const float dz) const; - const Vector& IdealPosition(CBaseEntity* pEnemy) const; + int m_iLevel; + float m_flLevelSpeed; - void UpdateBodyControllers(void); + CBeam* m_pBeam; + CSprite* m_pSprite; - void CreateBeam(const Vector& src, const Vector& target, int width); - void DestroyBeam(void); - void UpdateBeam(const Vector& src, const Vector& target); + BOOL m_fAttacking; + BOOL m_fLockHeight; + BOOL m_fLockYaw; - void SetupBeamPoints(CBaseEntity* pEnemy, Vector* vecleft, Vector* vecRight); - void UpdateBeamPoints(CBaseEntity* pEnemy, Vector* vecTarget); + int m_iWasHit; + float m_flTakeHitTime; - void CreateGlow(void); - void DestroyGlow(void); - void EyeOff(void); - void EyeOn(int level); - void EyeUpdate(void); - void CreateBeam(); + float m_flHitTime; + float m_flNextMeleeTime; + float m_flNextRangeTime; + float m_flDeathStartTime; - void SetYawSpeed(); - BOOL CheckMeleeAttack1(float flDot, float flDist); - BOOL CheckRangeAttack1(float flDot, float flDist); + BOOL m_fFirstSighting; + BOOL m_fTopLevelLocked; + float m_flLastBlinkTime; + float m_flLastBlinkInterval; + float m_flLastEventTime; - float m_flInitialYaw; - Vector m_spawnAngles; - Vector m_vecLevels[NUM_PITWORM_LEVELS]; + static const char* pHitGroundSounds[]; + static const char* pAngrySounds[]; + static const char* pSwipeSounds[]; + static const char* pShootSounds[]; - CBeam* m_pBeam; - float m_flBeamYaw; - float m_flBeamTime; - BOOL m_fBeamOn; - BOOL m_fActivated; - CSprite* m_pEyeGlow; - int m_eyeBrightness; - float m_painSoundTime; - float m_slowMode; - float m_slowTime; - Vector m_vecGoalAngles; - Vector m_vecCurAngles; - Vector m_eyes; - float m_flDamageTime; - float m_flDamage; - float m_flPlayerDamage; - BOOL m_fBlink; - int m_iLaserHitTimes; - - float m_flNextAttackTime; - float m_flNextIdleSoundTime; - - static const char* pHitSilo[]; - static const char* pClangSounds[]; - static const char* pAngrySounds[]; - static const char* pSwipeSounds[]; - static const char* pPainSounds[]; - static const char* pFlinchSounds[]; - - static const char* pAlertSounds[]; - static const char* pIdleSounds[]; - static const char* pDeathSounds[]; + static const char* pPainSounds[]; + static const char* pAlertSounds[]; + static const char* pIdleSounds[]; + static const char* pDeathSounds[]; + static const char* pAttackSounds[]; }; LINK_ENTITY_TO_CLASS(monster_pitworm, CPitWorm) LINK_ENTITY_TO_CLASS(monster_pitworm_up, CPitWorm) -#define PITWORM_HEIGHT 584 -#define PITWORM_EYE_OFFSET Vector(0, 0, 445) -#define PITWORM_EYEBLAST_ATTACK_DIST 460 // 464 -#define PITWORM_EYEBLAST_DURATION 3.03f // 0.49 approximatly. (49 miliseconds) +#define PITWORM_EYE_OFFSET Vector(0, 0, 300) #define PITWORM_CONTROLLER_EYE_YAW 0 #define PITWORM_CONTROLLER_EYE_PITCH 1 @@ -169,29 +165,6 @@ LINK_ENTITY_TO_CLASS(monster_pitworm_up, CPitWorm) #define PITWORM_EYE_PITCH_MAX 45 #define PITWORM_EYE_YAW_MIN -45 #define PITWORM_EYE_YAW_MAX 45 -#define PITWORM_BODY_YAW_MIN -50 -#define PITWORM_BODY_YAW_MAX 50 - -#define PITWORM_LEVEL0 0 // Pitworm's 'foot' level | when player is at First level 1. -#define PITWORM_LEVEL1 1 // First level | player goes to waste station door 1 or 2. -#define PITWORM_LEVEL2 2 // Second level | player goes to narrow corridor that leads to stairs. -#define PITWORM_LEVEL3 3 // Third level | entry room, steam vent and valve pressure controls. - -#define PITWORM_LEVEL0_HEIGHT -632 // Pitworm's 'foot' level | when player is at First level 1. | (Hammer units) -#define PITWORM_LEVEL1_HEIGHT -48 // First level | player goes to waste station door 1 or 2. | (Hammer units) -#define PITWORM_LEVEL2_HEIGHT 208 // Second level | player goes to narrow corridor that leads to stairs. | (Hammer units) -#define PITWORM_LEVEL3_HEIGHT 304 // Third level | entry room, steam vent and valve pressure controls. | (Hammer units) - - -#define PITWORM_LEVEL0_VIEWOFFSET Vector(0, 0, PITWORM_HEIGHT) -#define PITWORM_LEVEL1_VIEWOFFSET Vector(0, 0, 256) -#define PITWORM_LEVEL2_VIEWOFFSET Vector(0, 0, 96) -#define PITWORM_LEVEL3_VIEWOFFSET PITWORM_LEVEL2_VIEWOFFSET - -#define bits_MEMORY_CHILDPAIR ( bits_MEMORY_CUSTOM1 ) -#define bits_MEMORY_ADVANCE_NODE ( bits_MEMORY_CUSTOM2 ) -#define bits_MEMORY_COMPLETED_NODE ( bits_MEMORY_CUSTOM3 ) -#define bits_MEMORY_FIRED_NODE ( bits_MEMORY_CUSTOM4 ) //========================================================= // Monster's Anim Events Go Here @@ -205,103 +178,108 @@ LINK_ENTITY_TO_CLASS(monster_pitworm_up, CPitWorm) //========================================================= TYPEDESCRIPTION CPitWorm::m_SaveData[] = { - DEFINE_FIELD(CPitWorm, m_avelocity, FIELD_VECTOR), + DEFINE_FIELD(CPitWorm, m_flNextPainSound, FIELD_TIME), - DEFINE_FIELD(CPitWorm, m_vecTarget, FIELD_VECTOR), - DEFINE_FIELD(CPitWorm, m_posTarget, FIELD_POSITION_VECTOR), - DEFINE_FIELD(CPitWorm, m_vecDesired, FIELD_VECTOR), - DEFINE_FIELD(CPitWorm, m_posDesired, FIELD_POSITION_VECTOR), - DEFINE_FIELD(CPitWorm, m_flMinZ, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_flMaxZ, FIELD_FLOAT), + DEFINE_FIELD(CPitWorm, m_vecTarget, FIELD_POSITION_VECTOR), + DEFINE_FIELD(CPitWorm, m_posTarget, FIELD_POSITION_VECTOR), + DEFINE_FIELD(CPitWorm, m_vecDesired, FIELD_POSITION_VECTOR), + DEFINE_FIELD(CPitWorm, m_posDesired, FIELD_POSITION_VECTOR), - DEFINE_FIELD(CPitWorm, m_flLastSeen, FIELD_TIME), - DEFINE_FIELD(CPitWorm, m_flPrevSeen, FIELD_TIME), - DEFINE_FIELD(CPitWorm, m_iLevel, FIELD_INTEGER), - DEFINE_FIELD(CPitWorm, m_flAdj, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_distDesired, FIELD_FLOAT), + DEFINE_FIELD(CPitWorm, m_offsetBeam, FIELD_FLOAT), + DEFINE_FIELD(CPitWorm, m_posBeam, FIELD_POSITION_VECTOR), + DEFINE_FIELD(CPitWorm, m_vecBeam, FIELD_POSITION_VECTOR), + DEFINE_FIELD(CPitWorm, m_angleBeam, FIELD_POSITION_VECTOR), + DEFINE_FIELD(CPitWorm, m_flBeamExpireTime, FIELD_TIME), + DEFINE_FIELD(CPitWorm, m_flBeamDir, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_flInitialYaw, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_spawnAngles, FIELD_VECTOR), - DEFINE_ARRAY(CPitWorm, m_vecLevels, FIELD_POSITION_VECTOR, NUM_PITWORM_LEVELS), - DEFINE_FIELD(CPitWorm, m_pBeam, FIELD_CLASSPTR), - DEFINE_FIELD(CPitWorm, m_flBeamTime, FIELD_TIME), - DEFINE_FIELD(CPitWorm, m_flBeamYaw, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_fBeamOn, FIELD_BOOLEAN), - DEFINE_FIELD(CPitWorm, m_pEyeGlow, FIELD_CLASSPTR), - DEFINE_FIELD(CPitWorm, m_eyeBrightness, FIELD_INTEGER), + DEFINE_ARRAY(CPitWorm, m_flLevels, FIELD_FLOAT, NUM_PITWORM_LEVELS), + DEFINE_ARRAY(CPitWorm, m_flTargetLevels, FIELD_FLOAT, NUM_PITWORM_LEVELS), - DEFINE_FIELD(CPitWorm, m_vecGoalAngles, FIELD_VECTOR), - DEFINE_FIELD(CPitWorm, m_vecCurAngles, FIELD_VECTOR), - DEFINE_FIELD(CPitWorm, m_flNextAttackTime, FIELD_TIME), - DEFINE_FIELD(CPitWorm, m_flNextIdleSoundTime, FIELD_TIME), - DEFINE_FIELD(CPitWorm, m_fActivated, FIELD_BOOLEAN), - DEFINE_FIELD(CPitWorm, m_iLaserHitTimes, FIELD_INTEGER), - DEFINE_FIELD(CPitWorm, m_flDamage, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_fBlink, FIELD_BOOLEAN), - DEFINE_FIELD(CPitWorm, m_flPlayerDamage, FIELD_FLOAT), - DEFINE_FIELD(CPitWorm, m_vecEmemyPos, FIELD_VECTOR), - DEFINE_FIELD(CPitWorm, m_flNextBlink, FIELD_FLOAT), + DEFINE_FIELD(CPitWorm, m_flLastSeen, FIELD_TIME), + + DEFINE_FIELD(CPitWorm, m_iLevel, FIELD_INTEGER), + DEFINE_FIELD(CPitWorm, m_flLevelSpeed, FIELD_FLOAT), + + DEFINE_FIELD(CPitWorm, m_pBeam, FIELD_CLASSPTR), + DEFINE_FIELD(CPitWorm, m_pSprite, FIELD_CLASSPTR), + + DEFINE_FIELD(CPitWorm, m_fAttacking, FIELD_BOOLEAN), + DEFINE_FIELD(CPitWorm, m_fLockHeight, FIELD_BOOLEAN), + DEFINE_FIELD(CPitWorm, m_fLockYaw, FIELD_BOOLEAN), + + DEFINE_FIELD(CPitWorm, m_iWasHit, FIELD_INTEGER), + DEFINE_FIELD(CPitWorm, m_flTakeHitTime, FIELD_TIME), + + DEFINE_FIELD(CPitWorm, m_flHitTime, FIELD_TIME), + DEFINE_FIELD(CPitWorm, m_flNextMeleeTime, FIELD_TIME), + DEFINE_FIELD(CPitWorm, m_flNextRangeTime, FIELD_TIME), + DEFINE_FIELD(CPitWorm, m_flDeathStartTime, FIELD_TIME), + + DEFINE_FIELD(CPitWorm, m_fFirstSighting, FIELD_BOOLEAN), + DEFINE_FIELD(CPitWorm, m_fTopLevelLocked, FIELD_BOOLEAN), + + DEFINE_FIELD(CPitWorm, m_flLastBlinkTime, FIELD_TIME), + DEFINE_FIELD(CPitWorm, m_flLastBlinkInterval, FIELD_FLOAT), + DEFINE_FIELD(CPitWorm, m_flLastEventTime, FIELD_FLOAT), }; IMPLEMENT_SAVERESTORE(CPitWorm, CBaseMonster) - -const char *CPitWorm::pHitSilo[] = +const char* CPitWorm::pHitGroundSounds[] = { - "tentacle/te_strike1.wav", - "tentacle/te_strike2.wav", -}; - -const char* CPitWorm::pClangSounds[] = -{ - "pitworm/clang1.wav", - "pitworm/clang2.wav", - "pitworm/clang3.wav", + "tentacle/te_strike1.wav", + "tentacle/te_strike2.wav", }; const char* CPitWorm::pAngrySounds[] = { - "pitworm/pit_worm_angry1.wav", - "pitworm/pit_worm_angry2.wav", - "pitworm/pit_worm_angry3.wav", + "pitworm/pit_worm_angry1.wav", + "pitworm/pit_worm_angry2.wav", + "pitworm/pit_worm_angry3.wav", }; const char* CPitWorm::pSwipeSounds[] = { - "pitworm/pit_worm_attack_swipe1.wav", - "pitworm/pit_worm_attack_swipe2.wav", - "pitworm/pit_worm_attack_swipe3.wav", + "pitworm/pit_worm_attack_swipe1.wav", + "pitworm/pit_worm_attack_swipe2.wav", + "pitworm/pit_worm_attack_swipe3.wav", +}; + +const char* CPitWorm::pShootSounds[] = +{ + "debris/beamstart3.wav", + "debris/beamstart8.wav", }; const char* CPitWorm::pPainSounds[] = { - "pitworm/pit_worm_flinch2.wav", - "pitworm/pit_worm_flinch2.wav", - "pitworm/pit_worm_flinch2.wav", -}; - -const char* CPitWorm::pFlinchSounds[] = -{ - "pitworm/pit_worm_flinch1.wav", - "pitworm/pit_worm_flinch2.wav", + "pitworm/pit_worm_flinch1.wav", + "pitworm/pit_worm_flinch2.wav", }; const char* CPitWorm::pAlertSounds[] = { - "pitworm/pit_worm_alert.wav", + "pitworm/pit_worm_alert.wav", }; const char* CPitWorm::pIdleSounds[] = { - "pitworm/pit_worm_idle1.wav", - "pitworm/pit_worm_idle2.wav", - "pitworm/pit_worm_idle3.wav", + "pitworm/pit_worm_idle1.wav", + "pitworm/pit_worm_idle2.wav", + "pitworm/pit_worm_idle3.wav", }; const char* CPitWorm::pDeathSounds[] = { - "pitworm/pit_worm_death.wav", + "pitworm/pit_worm_death.wav", +}; + +const char *CPitWorm::pAttackSounds[] = +{ + "zombie/claw_strike1.wav", + "zombie/claw_strike2.wav", + "zombie/claw_strike3.wav" }; //========================================================= @@ -309,66 +287,69 @@ const char* CPitWorm::pDeathSounds[] = //========================================================= void CPitWorm::Spawn() { - Precache(); + Precache(); + SET_MODEL(ENT(pev), "models/pit_worm_up.mdl"); - pev->movetype = MOVETYPE_STEP; - pev->solid = SOLID_SLIDEBOX; + pev->movetype = MOVETYPE_FLY; + pev->solid = SOLID_BBOX; - SET_MODEL(ENT(pev), "models/pit_worm_up.mdl"); - UTIL_SetSize(pev, Vector(-64, -128, 0), Vector(64, 128, 64)); - UTIL_SetOrigin(pev, pev->origin); + UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64)); + UTIL_SetOrigin(pev, pev->origin); - pev->health = 150 * gSkillData.pwormHealth; - pev->view_ofs = PITWORM_EYE_OFFSET; + pev->flags |= FL_MONSTER|FL_FLY; + pev->takedamage = DAMAGE_AIM; - m_flFieldOfView = -1; + pev->health = gSkillData.pwormHealth; + pev->max_health = pev->health; - pev->sequence = 0; - ResetSequenceInfo(); + pev->view_ofs = PITWORM_EYE_OFFSET; + m_bloodColor = BLOOD_COLOR_GREEN; + m_flFieldOfView = 0.5; - InitBoneControllers(); + pev->sequence = 0; + ResetSequenceInfo(); - SetThink(&CPitWorm::StartupThink); - pev->nextthink = gpGlobals->time + 0.1; + m_flTorsoYaw = 0; + m_flHeadYaw = 0; + m_flHeadPitch = 0; + m_flIdealTorsoYaw = 0; + m_flIdealHeadYaw = 0; + m_flIdealHeadPitch = 0; - m_spawnAngles = pev->angles; - m_flInitialYaw = m_spawnAngles.y; - pev->ideal_yaw = m_flInitialYaw; + InitBoneControllers(); - m_IdealMonsterState = MONSTERSTATE_IDLE;// Assume monster will be idle, until proven otherwise + SetThink(&CPitWorm::StartupThink); + SetTouch(&CPitWorm::HitTouch); + pev->nextthink = gpGlobals->time + 0.1; - m_IdealActivity = ACT_IDLE; + m_vecDesired = Vector(1,0,0); + m_posDesired = pev->origin; - m_flDistTooFar = 1024.0; - m_flDistLook = 2048.0; + m_fAttacking = FALSE; + m_fLockHeight = FALSE; + m_fFirstSighting = FALSE; + m_flBeamExpireTime = gpGlobals->time; + m_iLevel = 0; + m_fLockYaw = FALSE; - // set eye position - SetEyePosition(); + m_iWasHit = 0; + m_flTakeHitTime = 0; + m_flHitTime = 0; + m_flLevelSpeed = 10; - m_flLastSeen = 0.0f; - m_flPrevSeen = 0.0f; - m_iLevel = PITWORM_LEVEL1; - - m_pBeam = NULL; - m_flBeamYaw = 0.0f; - m_fBeamOn = FALSE; - m_eyeBrightness = 0; - m_slowMode = 4; - m_afCapability = bits_CAP_MELEE_ATTACK1; - m_slowTime = gpGlobals->time; - m_vecCurAngles = Vector(0, pev->angles.y, 0); - m_vecGoalAngles = Vector(0, pev->angles.y, 0); - m_flNextAttackTime = gpGlobals->time; - m_flNextIdleSoundTime = gpGlobals->time; - m_bloodColor = BLOOD_COLOR_GREEN; - m_fActivated = FALSE; - m_vecEmemyPos = g_vecZero; - m_flNextBlink = gpGlobals->time; - m_fBlink = FALSE; - m_iLaserHitTimes = 0; - - // Create the eye glow. - CreateGlow(); + m_fTopLevelLocked = FALSE; + m_flLastBlinkTime = gpGlobals->time; + m_flLastBlinkInterval = gpGlobals->time; + m_flLastEventTime = gpGlobals->time; + m_flTargetLevels[3] = pev->origin.z; + m_flLevels[3] = pev->origin.z - 350.0; + m_flTargetLevels[2] = pev->origin.z; + m_flLevels[2] = pev->origin.z - 300.0; + m_flTargetLevels[1] = pev->origin.z; + m_flLevels[1] = pev->origin.z - 300.0; + m_flTargetLevels[0] = pev->origin.z; + m_flLevels[0] = pev->origin.z - 300.0;; + m_pBeam = 0; } //========================================================= @@ -376,33 +357,52 @@ void CPitWorm::Spawn() //========================================================= void CPitWorm::Precache() { - PRECACHE_MODEL("models/pit_worm_up.mdl"); + PRECACHE_MODEL("models/pit_worm_up.mdl"); - PRECACHE_SOUND_ARRAY(pHitSilo); + PRECACHE_SOUND("pitworm/pit_worm_alert.wav"); + PRECACHE_SOUND("pitworm/pit_worm_attack_eyeblast.wav"); + PRECACHE_SOUND("pitworm/pit_worm_attack_eyeblast_impact.wav"); + PRECACHE_SOUND("pitworm/pit_worm_death.wav"); - PRECACHE_SOUND("pitworm/pit_worm_alert.wav"); - PRECACHE_SOUND("pitworm/pit_worm_attack_eyeblast.wav"); - PRECACHE_SOUND("pitworm/pit_worm_attack_eyeblast_impact.wav"); - PRECACHE_SOUND("pitworm/pit_worm_death.wav"); - PRECACHE_SOUND("pitworm/pit_worm_alert(scream).wav"); + PRECACHE_SOUND_ARRAY(pHitGroundSounds); + PRECACHE_SOUND_ARRAY(pAngrySounds); + PRECACHE_SOUND_ARRAY(pSwipeSounds); + PRECACHE_SOUND_ARRAY(pIdleSounds); + PRECACHE_SOUND_ARRAY(pPainSounds); + PRECACHE_SOUND_ARRAY(pAttackSounds); - PRECACHE_SOUND_ARRAY(pClangSounds); - PRECACHE_SOUND_ARRAY(pAngrySounds); - PRECACHE_SOUND_ARRAY(pSwipeSounds); - PRECACHE_SOUND_ARRAY(pFlinchSounds); - PRECACHE_SOUND_ARRAY(pIdleSounds); - PRECACHE_SOUND_ARRAY(pPainSounds); - - PRECACHE_MODEL("sprites/gworm_beam_02.spr"); - PRECACHE_MODEL("sprites/glow_grn.spr"); + PRECACHE_MODEL("sprites/laserbeam.spr"); + PRECACHE_MODEL("sprites/tele1.spr"); } -//========================================================= -// Classify -//========================================================= -int CPitWorm::Classify(void) +BOOL CPitWorm::FVisible(CBaseEntity *pEntity) { - return CLASS_ALIEN_MONSTER; + if( FBitSet( pEntity->pev->flags, FL_NOTARGET ) ) + return FALSE; + + if( ( pev->waterlevel != 3 && pEntity->pev->waterlevel == 3 ) + || ( pev->waterlevel == 3 && pEntity->pev->waterlevel == 0 ) ) + return FALSE; + + TraceResult tr; + Vector vecLookerOrigin; + Vector vecLookerAngle; + + GetAttachment(0, vecLookerOrigin, vecLookerAngle); + UTIL_TraceLine( vecLookerOrigin, pEntity->EyePosition(), ignore_monsters, ignore_glass, ENT( pev ), &tr ); + + return tr.flFraction == 1.0; +} + +BOOL CPitWorm::FVisible(const Vector& vecOrigin) +{ + TraceResult tr; + Vector vecLookerOrigin; + Vector vecLookerAngle; + + GetAttachment(0, vecLookerOrigin, vecLookerAngle); + UTIL_TraceLine( vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, ENT( pev ), &tr ); + return tr.flFraction == 1.0; } //========================================================= @@ -410,7 +410,7 @@ int CPitWorm::Classify(void) //========================================================= void CPitWorm::IdleSound(void) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), VOL_NORM, ATTN_NORM); + EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), VOL_NORM, PITWORM_ATTN); } //========================================================= @@ -418,7 +418,7 @@ void CPitWorm::IdleSound(void) //========================================================= void CPitWorm::AlertSound(void) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), VOL_NORM, ATTN_NORM); + EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAlertSounds), VOL_NORM, PITWORM_ATTN); } //========================================================= @@ -426,7 +426,16 @@ void CPitWorm::AlertSound(void) //========================================================= void CPitWorm::DeathSound(void) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), VOL_NORM, ATTN_NORM); + EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), VOL_NORM, PITWORM_ATTN); +} + +void CPitWorm::PainSound(void) +{ + if (m_flNextPainSound <= gpGlobals->time) + { + m_flNextPainSound = gpGlobals->time + RANDOM_LONG(2, 5); + EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), VOL_NORM, PITWORM_ATTN); + } } //========================================================= @@ -434,15 +443,7 @@ void CPitWorm::DeathSound(void) //========================================================= void CPitWorm::AngrySound(void) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAngrySounds), VOL_NORM, ATTN_NORM); -} - -//========================================================= -// FlinchSound -//========================================================= -void CPitWorm::FlinchSound(void) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pFlinchSounds), VOL_NORM, ATTN_NORM); + EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAngrySounds), VOL_NORM, PITWORM_ATTN); } //========================================================= @@ -450,7 +451,7 @@ void CPitWorm::FlinchSound(void) //========================================================= void CPitWorm::SwipeSound(void) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pSwipeSounds), VOL_NORM, ATTN_NORM); + EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pSwipeSounds), VOL_NORM, PITWORM_ATTN); } //========================================================= @@ -458,22 +459,7 @@ void CPitWorm::SwipeSound(void) //========================================================= void CPitWorm::BeamSound(void) { - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitworm/pit_worm_attack_eyeblast.wav", VOL_NORM, ATTN_NORM); -} - -void CPitWorm::pPainSound(void) -{ - EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), VOL_NORM, ATTN_NORM); -} - - -//========================================================= -// SetObjectCollisionBox -//========================================================= -void CPitWorm::SetObjectCollisionBox(void) -{ - pev->absmin = pev->origin + Vector(-96, -310, 0); - pev->absmax = pev->origin + Vector(96, 32, 512); + EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitworm/pit_worm_attack_eyeblast.wav", VOL_NORM, PITWORM_ATTN); } //========================================================= @@ -481,185 +467,110 @@ void CPitWorm::SetObjectCollisionBox(void) //========================================================= void CPitWorm::HandleAnimEvent(MonsterEvent_t *pEvent) { - if(gpGlobals->time - m_slowTime <= 3.5) - return; + switch (pEvent->event) + { + case PITWORM_AE_SWIPE: // bang + { + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pHitGroundSounds), VOL_NORM, ATTN_NORM, 0, 100 + RANDOM_FLOAT(-5,5)); - switch (pEvent->event) - { - case PITWORM_AE_SWIPE: // bang - { - Vector vecSrc, vecAngles; - GetAttachment(1, vecSrc, vecAngles); - Vector mins = pev->origin - Vector( 360, 430, 0 ); - Vector maxs = pev->origin + Vector( 410, 100, 800 ); + if (pev->sequence == 2) + UTIL_ScreenShake(pev->origin, 12.0, 100.0, 2.0, 100); + else + UTIL_ScreenShake(pev->origin, 4.0, 3.0, 1.0, 750.0); + } + break; + case PITWORM_AE_EYEBLAST_START: // start killing swing + { + if ( gpGlobals->time - m_flLastEventTime >= 1.1 ) + { + if (m_hEnemy) + { + m_posBeam = m_hEnemy->pev->origin; + m_posBeam.z += 24; - CBaseEntity *pList[10]; - int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, ( FL_CLIENT | FL_MONSTER ) ); + Vector vecEyePos, vecEyeAng; + GetAttachment(0, vecEyePos, vecEyeAng); - if( count ) - { - for( int i = 0; i < count; i++ ) - { - // only clients and monsters - 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. - { - pList[i]->TakeDamage(VARS(pev), VARS(pev), gSkillData.pwormDmgSwipe, DMG_CLUB | DMG_SLASH); - } - } - } + m_vecBeam = (m_posBeam - vecEyePos).Normalize(); + m_angleBeam = UTIL_VecToAngles(m_vecBeam); + UTIL_MakeVectors(m_angleBeam); + ShootBeam(); + m_fLockYaw = TRUE; + } + } + } + break; + case PITWORM_AE_EYEBLAST_END: // end killing swing + { + m_fLockYaw = TRUE; + } + break; + default: + CBaseMonster::HandleAnimEvent(pEvent); - // Shake the screen. - UTIL_EmitAmbientSound(ENT(pev), vecSrc, RANDOM_SOUND_ARRAY(pHitSilo), 1.0, ATTN_NORM, 0, 100); - UTIL_ScreenShake(vecSrc, 6.0, 3.0, 1.0, 768); - gpGlobals->force_retouch++; - } - break; - case PITWORM_AE_EYEBLAST_START: // start killing swing - { - // ALERT(at_console, "PITWORM_AE_EYEBLAST_START\n"); - - // Remove the beam if not NULL. - DestroyBeam(); - - Vector src, angles; - GetAttachment(0, src, angles); - - // Create a new beam. - CreateBeam(src, angles, 32); - - // Turn eye glow on. - EyeOn(255); - - // Reset beam yaw. - m_flBeamYaw = 0.0f; - m_flBeamTime = gpGlobals->time + PITWORM_EYEBLAST_DURATION; - } - break; - case PITWORM_AE_EYEBLAST_END: // end killing swing - {} - break; - default: - CBaseMonster::HandleAnimEvent(pEvent); - - } -} - - -void CPitWorm::SetYawSpeed( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 100; - break; - default: - ys = 90; - } - pev->yaw_speed = ys; -} - -BOOL CPitWorm::CheckRangeAttack1(float flDot, float flDist) -{ - if(flDist >= 1024 && m_flNextAttackTime > gpGlobals->time) - { - if(m_hEnemy != 0 && m_hEnemy->IsAlive()) - return TRUE; - - } - return FALSE; -} - -BOOL CPitWorm::CheckMeleeAttack1(float flDot, float flDist) -{ - if(flDist <= 192 && flDot > 0.7) - return TRUE; - - return FALSE; + } } void CPitWorm::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { - if ( ptr->iHitgroup == HITGROUP_HEAD ) - { - if (gpGlobals->time - m_slowTime > 3.5 ) - { - if ( m_flDamage >= 65) - { - m_slowTime = gpGlobals->time; - pev->sequence = LookupSequence("flinch1"); + if ( ptr->iHitgroup == HITGROUP_HEAD ) + { + if (gpGlobals->time > m_flTakeHitTime ) + { + pev->health -= flDamage; + if (pev->health <= 0) + { + pev->health = pev->max_health; + m_iWasHit = TRUE; + m_flTakeHitTime = m_flTakeHitTime + RANDOM_LONG(2,4); + } + } - if(m_fBeamOn) - { - DestroyBeam(); - EyeOff(); - } + UTIL_BloodDrips(ptr->vecEndPos, vecDir, m_bloodColor, flDamage * 10); + UTIL_BloodDecalTrace(ptr, m_bloodColor); - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitworm/pit_worm_flinch2.wav", 1, 0.8, 0, 100); - - m_flDamage = 0; - } - } - - if(gpGlobals->time - m_flDamageTime > 0.5) - m_flDamage = 0; - - if((pev->sequence != LookupSequence("scream") || pev->sequence != LookupSequence("flinch1")) && m_fActivated) - { - m_flDamage += flDamage; - - if(gpGlobals->time - m_flNextBlink >= 0.25) - m_fBlink = TRUE; - } - - UTIL_BloodDrips(ptr->vecEndPos, ptr->vecEndPos, m_bloodColor, flDamage * 10); - UTIL_BloodDecalTrace(ptr, m_bloodColor); - - m_flDamageTime = gpGlobals->time; - } - else - { - if (pev->dmgtime != gpGlobals->time || RANDOM_LONG(0, 10) >= 0 ) - { - UTIL_Ricochet(ptr->vecEndPos, RANDOM_LONG(0.5, 1.5)); - pev->dmgtime = gpGlobals->time; - } - } + if (m_hEnemy == 0) + { + m_hEnemy = Instance(pevAttacker); + } + if (pev->skin == 0) + { + pev->skin = 1; + m_flLastBlinkInterval = gpGlobals->time; + m_flLastBlinkTime = gpGlobals->time; + } + } + else + { + if (pev->dmgtime != gpGlobals->time || RANDOM_LONG(0, 10) >= 0 ) + { + UTIL_Ricochet(ptr->vecEndPos, RANDOM_LONG(0.5, 1.5)); + pev->dmgtime = gpGlobals->time; + } + } } -void CPitWorm::Activate() -{ - if(m_hTargetEnt == 0) - Remember(bits_MEMORY_ADVANCE_NODE); -} - - - void CPitWorm::CommandUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - switch (useType) - { - case USE_OFF: - //ALERT(at_console, "USE_OFF\n"); - break; - case USE_ON: - //ALERT(at_console, "USE_ON\n"); - break; - case USE_SET: - //ALERT(at_console, "USE_SET\n"); - break; - case USE_TOGGLE: - { - m_fSequenceFinished = TRUE; - pev->health = 0; + switch (useType) + { + case USE_ON: + CSoundEnt::InsertSound(bits_SOUND_WORLD, pActivator->pev->origin, 1024, 1.0); + //ALERT(at_console, "USE_ON\n"); + break; + case USE_OFF: + case USE_TOGGLE: + { + pev->takedamage = DAMAGE_NO; + pev->health = 0; - SetThink(&CPitWorm::DyingThink); - pev->nextthink = gpGlobals->time; - } - // ALERT(at_console, "USE_TOGGLE\n"); - break; - } + SetThink(&CPitWorm::DyingThink); + pev->nextthink = gpGlobals->time; + } + break; + default: + break; + } } @@ -668,21 +579,8 @@ void CPitWorm::CommandUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP //========================================================= int CPitWorm::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { - // Don't take any acid damage -- BigMomma's mortar is acid - if( bitsDamageType & DMG_ACID ) - flDamage = 0; - - if( !HasMemory( bits_MEMORY_PATH_FINISHED ) ) - { - if( pev->health <= flDamage ) - { - pev->health = flDamage + 1; - Remember( bits_MEMORY_ADVANCE_NODE | bits_MEMORY_COMPLETED_NODE ); - ALERT( at_aiconsole, "BM: Finished node health!!!\n" ); - } - } - - return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType ); + PainSound(); + return 0; } @@ -691,46 +589,62 @@ int CPitWorm::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float //========================================================= void CPitWorm::StartupThink(void) { - m_flAdj = 350; - Vector src = pev->origin; + CBaseEntity *pEntity = NULL; - CBaseEntity *pEntity = NULL; + pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tleveldead"); + if (pEntity) + { + ALERT(at_console, "level dead node set\n"); + m_flTargetLevels[0] = pEntity->pev->origin.z; + m_flLevels[0] = m_flTargetLevels[0] - 300; + } - pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tleveldead"); - if (pEntity) - m_vecLevels[PITWORM_LEVEL0] = pEntity->pev->origin; - else - m_vecLevels[PITWORM_LEVEL0] = Vector(src.x, src.y, PITWORM_LEVEL0_HEIGHT); + pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tlevel1"); + if (pEntity) + { + ALERT(at_console, "level 1 node set\n"); + m_flTargetLevels[1] = pEntity->pev->origin.z; + m_flLevels[1] = m_flTargetLevels[1] - 300; + } - pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tlevel1"); - if (pEntity) - m_vecLevels[PITWORM_LEVEL1] = pEntity->pev->origin; - else - m_vecLevels[PITWORM_LEVEL1] = Vector(src.x, src.y, PITWORM_LEVEL2_HEIGHT); + pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tlevel2"); + if (pEntity) + { + ALERT(at_console, "level 2 node set\n"); + m_flTargetLevels[2] = pEntity->pev->origin.z; + m_flLevels[2] = m_flTargetLevels[2] - 300; + } - pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tlevel2"); - if (pEntity) - m_vecLevels[PITWORM_LEVEL2] = pEntity->pev->origin; - else - m_vecLevels[PITWORM_LEVEL2] = Vector(src.x, src.y, PITWORM_LEVEL2_HEIGHT); + pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tlevel3"); + if (pEntity) + { + ALERT(at_console, "level 3 node set\n"); + m_flTargetLevels[3] = pEntity->pev->origin.z; + m_flLevels[3] = m_flTargetLevels[3] - 350; + } - pEntity = UTIL_FindEntityByTargetname(NULL, "pw_tlevel3"); - if (pEntity) - m_vecLevels[PITWORM_LEVEL3] = pEntity->pev->origin; - else - m_vecLevels[PITWORM_LEVEL3] = Vector(src.x, src.y, PITWORM_LEVEL3_HEIGHT); + m_iLevel = 2; + if (!FStringNull(pev->target)) + { + if (FStrEq(STRING(pev->target), "pw_level1")) + m_iLevel = 1; + else if (FStrEq(STRING(pev->target), "pw_level2")) + m_iLevel = 2; + else if (FStrEq(STRING(pev->target), "pw_level3")) + m_iLevel = 3; + else if (FStrEq(STRING(pev->target), "pw_leveldead")) + m_iLevel = 0; + } - // Set altitude limits. - m_flMinZ = m_vecLevels[PITWORM_LEVEL0].z; - m_flMaxZ = m_vecLevels[PITWORM_LEVEL3].z; + m_posDesired.z = m_flLevels[m_iLevel]; - // Set default level. - UTIL_SetOrigin(pev, IdealPosition(m_iLevel)); + Vector vecEyePos, vecEyeAng; + GetAttachment(0, vecEyePos, vecEyeAng); + pev->view_ofs = vecEyePos - pev->origin; - SetThink(&CPitWorm::HuntThink); - SetTouch(&CPitWorm::WormTouch); - SetUse(&CPitWorm::CommandUse); - pev->nextthink = gpGlobals->time + 0.1; + SetThink(&CPitWorm::HuntThink); + SetUse(&CPitWorm::CommandUse); + pev->nextthink = gpGlobals->time + 0.1; } //========================================================= @@ -738,9 +652,9 @@ void CPitWorm::StartupThink(void) //========================================================= void CPitWorm::StartupUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value) { - SetThink(&CPitWorm::HuntThink); - pev->nextthink = gpGlobals->time + 0.1; - SetUse(&CPitWorm::CommandUse); + SetThink(&CPitWorm::HuntThink); + pev->nextthink = gpGlobals->time + 0.1; + SetUse(&CPitWorm::CommandUse); } //========================================================= @@ -748,8 +662,8 @@ void CPitWorm::StartupUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP //========================================================= void CPitWorm::NullThink(void) { - StudioFrameAdvance(); - pev->nextthink = gpGlobals->time + 0.5; + StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.5; } //========================================================= @@ -757,43 +671,58 @@ void CPitWorm::NullThink(void) //========================================================= void CPitWorm::DyingThink(void) { - pev->nextthink = gpGlobals->time + 0.1; - GlowShellUpdate(); - DispatchAnimEvents(); - StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + GlowShellUpdate(); + DispatchAnimEvents(); + StudioFrameAdvance(); - if (pev->deadflag == DEAD_NO) - { - DestroyGlow(); - DeathSound(); - pev->deadflag = DEAD_DYING; - } + if (pev->deadflag == DEAD_DYING) + { + if ( gpGlobals->time - m_flDeathStartTime > 3.0 ) + { + ChangeLevel(); + } + if ( fabs(pev->origin.z - this->m_flLevels[0]) < 16.0 ) + { + pev->velocity = Vector(0, 0, 0); + pev->deadflag = DEAD_DEAD; + SetThink(&CBaseEntity::SUB_Remove); + pev->nextthink = gpGlobals->time + 0.1; + } + } + else + { + pev->deadflag = DEAD_DYING; + int deathAnim = LookupSequence("death"); + int iDir = 1; + m_posDesired.z = m_flLevels[0]; + pev->sequence = FindTransition(pev->sequence, deathAnim, &iDir); + if (iDir <= 0) + { + pev->frame = 255; + } + else + { + pev->frame = 0; + } + m_flLevelSpeed = 5; + ResetSequenceInfo(); + DeathSound(); - if (pev->deadflag == DEAD_DYING) - { - if (fabs(pev->origin.z - m_flMaxZ) < 16) - { - pev->velocity = Vector(0, 0, 0); - pev->deadflag = DEAD_DEAD; - } - } + if (m_pBeam) + { + UTIL_Remove(m_pBeam); + m_pBeam = NULL; + } + if (m_pSprite) + { + UTIL_Remove(m_pSprite); + m_pSprite = NULL; + } - if(m_fBeamOn) - DestroyBeam(); - - if (m_fSequenceFinished) - { - if (pev->sequence != LookupSequence("death")) - { - pev->sequence = LookupSequence("death"); - pev->frame = 0; - pev->framerate = 0.2f; // Set the framerate manually until we find a better fix. - } - else - { - UTIL_Remove(this); - } - } + SetUse(NULL); + SetTouch(NULL); + } } //========================================================= @@ -801,226 +730,141 @@ void CPitWorm::DyingThink(void) //========================================================= void CPitWorm::HuntThink(void) { - pev->nextthink = gpGlobals->time + 0.1; - GlowShellUpdate(); - DispatchAnimEvents(); - StudioFrameAdvance(); + pev->nextthink = gpGlobals->time + 0.1; + GlowShellUpdate(); + DispatchAnimEvents(); + StudioFrameAdvance(); - // Update the eye glow. - EyeUpdate(); + if (m_pBeam) + { + if (m_hEnemy != 0 && m_flBeamExpireTime > gpGlobals->time) + { + StrafeBeam(); + } + else + { + UTIL_Remove(m_pBeam); + m_pBeam = NULL; + UTIL_Remove(m_pSprite); + m_pSprite = NULL; + } + } - if(!m_fActivated) - { - if(m_hEnemy == 0) - { - Look(4096); - m_hEnemy = BestVisibleEnemy(); - } - else - { - if((pev->origin - m_hEnemy->pev->origin).Length() <= 936) - { - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitworm/pit_worm_alert(scream).wav", 1, 0.8, 0, 100); - pev->frame = 0; - pev->sequence = LookupSequence("scream"); - ResetSequenceInfo(); - m_fActivated = TRUE; - } - else - { - pev->nextthink = gpGlobals->time + 0.01f; - return; - } - } - } + if (pev->health <= 0) + { + SetThink(&CPitWorm::DyingThink); + m_fSequenceFinished = TRUE; + } + else + { + if ( (gpGlobals->time - m_flLastBlinkTime) >= 6.0 && !m_pBeam ) + { + pev->skin = 1; + m_flLastBlinkInterval = gpGlobals->time; + m_flLastBlinkTime = gpGlobals->time; + } - if (m_hEnemy) - { - // Update body controllers. - UpdateBodyControllers(); + if (pev->skin) + { + if ( gpGlobals->time - m_flLastBlinkInterval >= 0.0 ) + { + if ( pev->skin == 5 ) + pev->skin = 0; + else + pev->skin++; + m_flLastBlinkInterval = gpGlobals->time; + } + } + } - //float flDist = (m_hEnemy->pev->origin - m_vecLevels[m_iLevel]).Length(); - //ALERT(at_console, "pitworm: Distance from eye %f\n", flDist); + if (m_iWasHit) + { + int iDir = 1; + const char* flinchAnim = RANDOM_LONG(0,1) ? "flinch1" : "flinch2"; + pev->sequence = FindTransition(pev->sequence, LookupSequence(flinchAnim), &iDir); + if (iDir > 0) + { + pev->frame = 0; + } + else + { + pev->frame = 255; + } + ResetSequenceInfo(); + m_iWasHit = FALSE; + PainSound(); + } + else if (m_fSequenceFinished) + { + int oldSeq = pev->sequence; + if ( m_fAttacking ) + { + m_fLockHeight = FALSE; + m_fLockYaw = FALSE; + m_fAttacking = FALSE; + m_flNextMeleeTime = gpGlobals->time + 0.25; + } + NextActivity(); + if (pev->sequence != oldSeq || !m_fSequenceLoops) + { + pev->frame = 0; + ResetSequenceInfo(); + } + } - // Update beam if we need to. - if (m_fBeamOn) - { - if (m_flBeamTime > gpGlobals->time && !m_fSequenceFinished) - { - Vector src, target, angles; - GetAttachment(0, src, angles); - UpdateBeamPoints(m_hEnemy, &target); + if (m_hEnemy != 0) + { + if (FVisible(m_hEnemy)) + { + m_flLastSeen = gpGlobals->time; + m_posTarget = m_hEnemy->pev->origin; + m_posTarget.z += 24; + Vector vecEyePos, vecEyeAng; + GetAttachment(0, vecEyePos, vecEyeAng); + m_vecTarget = (m_posTarget - vecEyePos).Normalize(); + m_vecDesired = m_vecTarget; + } + } - TraceResult tr; - UTIL_TraceLine(src, target + ((target - src).Normalize() * 1000), dont_ignore_monsters, ENT(pev), &tr); - - UpdateBeam(src, tr.vecEndPos); - - // Test to see if we hit - CBaseEntity *pHurt = CBaseEntity::Instance(tr.pHit); - - if (pHurt->pev->takedamage) - { - if(m_flPlayerDamage <= gSkillData.pwormDmgBeam) - { - pHurt->TakeDamage(VARS(pev), VARS(pev), 1, DMG_GENERIC); - UTIL_ScreenShake(pHurt->pev->origin, 1, 10, 0.1, 1); - - if(m_iLaserHitTimes >= 15) - { - UTIL_BloodDrips(tr.vecEndPos, tr.vecEndPos, BLOOD_COLOR_RED, 128); - m_iLaserHitTimes = 0; - } - - } - m_flPlayerDamage += gSkillData.pwormDmgBeam/100; - } - else - { - UTIL_DecalTrace(&tr, RANDOM_LONG(1,2)); - - if(m_iLaserHitTimes >= 8) - { - UTIL_Sparks(tr.vecEndPos); - m_iLaserHitTimes = 0; - } - } - - m_iLaserHitTimes++; - } - else - { - // Remove the beam. - DestroyBeam(); - - // Turn eye glow off. - EyeOff(); - - // Reset beam yaw. - m_flBeamYaw = 0.0f; - - // Reset beam time. - m_flBeamTime = 0.0f; - } - - pev->nextthink = gpGlobals->time + 0.01f; - return; - } - } - - switch (m_iLevel) - { - case PITWORM_LEVEL0: pev->view_ofs = PITWORM_EYE_OFFSET; break; - case PITWORM_LEVEL1: pev->view_ofs = PITWORM_EYE_OFFSET; break; - case PITWORM_LEVEL2: pev->view_ofs = PITWORM_EYE_OFFSET; break; - case PITWORM_LEVEL3: pev->view_ofs = PITWORM_EYE_OFFSET; break; - } - { - float currentZ = pev->origin.z; - float desiredZ = m_posDesired.z - m_flAdj; - - if (currentZ > desiredZ) - { - pev->origin.z -= 8; - - if (pev->origin.z < desiredZ) - pev->origin.z = desiredZ; - } - else if (currentZ < desiredZ) - { - pev->origin.z += 8; - - if (pev->origin.z > desiredZ) - pev->origin.z = desiredZ; - } - } - - // if dead, force cancelation of current animation - if (pev->health <= 0) - { - SetThink(&CPitWorm::DyingThink); - m_fSequenceFinished = TRUE; - return; - } - - // get new sequence - if (m_fSequenceFinished) - { - pev->frame = 0; - NextActivity(); - ResetSequenceInfo(); - } - - // look for current enemy - if (m_hEnemy != 0) - { - // Update level based on enemy's altitude (z). - m_iLevel = Level(m_hEnemy->pev->origin.z); - - if (FVisible(m_hEnemy)) - { - if (m_flLastSeen < gpGlobals->time - 5) - m_flPrevSeen = gpGlobals->time; - - m_flLastSeen = gpGlobals->time; - m_posTarget = m_hEnemy->pev->origin; - m_vecTarget = (m_posTarget - pev->origin).Normalize(); - m_vecDesired = m_vecTarget; - m_posDesired = IdealPosition(m_iLevel); - } - } - - if (m_flNextIdleSoundTime < gpGlobals->time) - { - //IdleSound(); - // Use flinch sounds. - FlinchSound(); - m_flNextIdleSoundTime = gpGlobals->time + RANDOM_LONG(4.0f, 4.1f); - } - - // don't go too high - if (m_posDesired.z > m_flMaxZ) - m_posDesired.z = m_flMaxZ; - - // don't go too low - if (m_posDesired.z < m_flMinZ) - m_posDesired.z = m_flMinZ; - - if(RANDOM_LONG(0, 20) == 5 && gpGlobals->time - m_flNextBlink >= RANDOM_FLOAT(3,5)) - { - m_fBlink = TRUE; - m_flNextBlink = gpGlobals->time; - } - - if(gpGlobals->time - m_flNextBlink >= 0.05 && m_fBlink && !m_fBeamOn) - { - if(pev->skin < 3) - { - pev->skin++; - m_flNextBlink = gpGlobals->time; - } - else - { - pev->skin = 0; - m_fBlink = FALSE; - } - } + if (m_posDesired.z > m_flLevels[3]) + { + m_posDesired.z = m_flLevels[3]; + } + else if (m_posDesired.z < m_flLevels[0]) + { + m_posDesired.z = m_flLevels[0]; + } + ChangeLevel(); + if (m_hEnemy != 0 && !m_pBeam) + { + TrackEnemy(); + } } //========================================================= // //========================================================= -void CPitWorm::WormTouch(CBaseEntity* pOther) +void CPitWorm::HitTouch(CBaseEntity* pOther) { - return; -} + TraceResult tr = UTIL_GetGlobalTrace(); -//========================================================= -// -//========================================================= -int CPitWorm::CanPlaySequence(BOOL fDisregardState) -{ - return TRUE; + if (pOther->pev->modelindex == pev->modelindex) + return; + + if (m_flHitTime > gpGlobals->time) + return; + + if( tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex ) + return; + + if (pOther->pev->takedamage) + { + pOther->TakeDamage(pev, pev, gSkillData.pwormDmgSwipe, DMG_CRUSH|DMG_SLASH); + pOther->pev->punchangle.z = 15; + pOther->pev->velocity.z += 200; + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackSounds), VOL_NORM, ATTN_NORM, 0, 100 + RANDOM_FLOAT(-5,5)); + m_flHitTime = gpGlobals->time + 1.0; + } } //========================================================= @@ -1028,407 +872,505 @@ int CPitWorm::CanPlaySequence(BOOL fDisregardState) //========================================================= void CPitWorm::NextActivity() { - if(!m_fActivated) - return; + UTIL_MakeAimVectors(pev->angles); - UTIL_MakeAimVectors(pev->angles); + if (m_hEnemy) + { + if (!m_hEnemy->IsAlive()) + { + m_hEnemy = 0; + m_flIdealHeadYaw = 0; + } + } - Vector forward = gpGlobals->v_forward; - forward.z = 0; + if (gpGlobals->time > m_flLastSeen + 15) + { + if (m_hEnemy != 0) + { + if ((pev->origin - m_hEnemy->pev->origin).Length() > 700) + m_hEnemy = NULL; + } + } - float flDist = (m_vecDesired - m_vecLevels[m_iLevel]).Length(); - float flDot = DotProduct(m_vecDesired, forward); - float flDotSpawnAngles = DotProduct(m_vecDesired, m_spawnAngles); + if (m_hEnemy == 0) + { + Look(4096); + m_hEnemy = BestVisibleEnemy(); + } - if (m_hEnemy == 0) - { - m_flLastSeen = gpGlobals->time; - m_hEnemy = UTIL_PlayerByIndex(1); - } + if (m_hEnemy != 0 || m_fFirstSighting) + { + if (m_iWasHit) + { + const char* flinchAnim = RANDOM_LONG(0,1) ? "flinch1" : "flinch2"; + pev->sequence = LookupSequence(flinchAnim); + m_iWasHit = FALSE; + PainSound(); + m_fLockHeight = 0; + m_fLockYaw = 0; + m_fAttacking = 0; + } + else if (pev->origin.z == m_posDesired.z) + { + if ( abs((int)floor(m_flIdealTorsoYaw - m_flTorsoYaw)) > 10 || !ClawAttack() ) + { + if ( RANDOM_LONG(0, 2) == 0 ) + { + IdleSound(); + } - if (m_hEnemy == 0) - { - Look(4096); - m_hEnemy = BestVisibleEnemy(); - } - - if (m_hEnemy != 0) - { - - if(gpGlobals->time - m_slowTime <= 3.5) - return; - - m_vecDesired = m_hEnemy->pev->origin; - flDist = (m_vecDesired - m_vecLevels[m_iLevel]).Length(); - flDot = DotProduct(m_vecDesired, forward); - flDotSpawnAngles = DotProduct(m_vecDesired, Vector(0, -1, 0)); - - if (m_flLastSeen + 5 > gpGlobals->time && (m_flNextAttackTime < gpGlobals->time)) - { - Vector enemyDir = m_hEnemy->pev->origin - pev->origin; - Vector spawnAngles = m_spawnAngles; - Vector up = CrossProduct(enemyDir, spawnAngles); - float dist = UTIL_AngleDistance(m_hEnemy->pev->origin.y, pev->origin.y); - - if (m_iLevel < PITWORM_LEVEL3) - { - if (FVisible(m_hEnemy) && flDot > 0.95f || dist <= -140 && dist >= -326) - { - if (flDist > PITWORM_EYEBLAST_ATTACK_DIST) - { - pev->sequence = LookupSequence("eyeblast"); - BeamSound(); - } - else - { - pev->sequence = LookupSequence("attacklow"); - SwipeSound(); - } - } - else - { - if (up.z < 0) - { - pev->sequence = LookupSequence("doorclaw2"); - } - else - { - if (m_iLevel < PITWORM_LEVEL2) - { - pev->sequence = LookupSequence("doorclaw3"); - } - else - { - pev->sequence = LookupSequence("doorclaw1"); - } - } - } - } - else - { - if (flDist > PITWORM_EYEBLAST_ATTACK_DIST) - { - pev->sequence = LookupSequence("eyeblast"); - BeamSound(); - } - else - { - if (up.z < 0) - { - pev->sequence = LookupSequence("platclaw1"); - - if (RANDOM_LONG(0, 1) == 1) SwipeSound(); - } - else - { - pev->sequence = LookupSequence("platclaw2"); - if (RANDOM_LONG(0, 1) == 1) SwipeSound(); - } - } - } - - m_flNextAttackTime = gpGlobals->time + RANDOM_FLOAT(3, 3.1f); - return; - } - } - - if (m_hEnemy) - { - pev->sequence = LookupSequence("idle2"); - return; - } - - FloatSequence(); + pev->sequence = LookupSequence("idle2"); + m_fLockHeight = FALSE; + m_fLockYaw = FALSE; + m_fAttacking = FALSE; + } + } + else + { + if ( RANDOM_LONG(0, 2) == 0 ) + { + IdleSound(); + } + pev->sequence = LookupSequence("idle"); + m_fLockHeight = FALSE; + m_fLockYaw = FALSE; + m_fAttacking = FALSE; + } + } + if (m_hEnemy != 0 && !m_fFirstSighting) + { + EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitworm/pit_worm_alert.wav", VOL_NORM, 0.1, 0, 100); + m_fFirstSighting = TRUE; + pev->sequence = LookupSequence("scream"); + } } -//========================================================= -// FloatSequence -//========================================================= -void CPitWorm::FloatSequence(void) +void CPitWorm::EyeLight(const Vector &vecEyePos) { - switch (RANDOM_LONG(0, 1)) - { - case 0: - pev->sequence = LookupSequence("idle"); - break; - - case 1: - pev->sequence = LookupSequence("idle2"); - break; - } + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_ELIGHT ); + WRITE_SHORT( entindex() ); // entity, attachment + WRITE_COORD( vecEyePos.x ); // origin + WRITE_COORD( vecEyePos.y ); + WRITE_COORD( vecEyePos.z ); + WRITE_COORD( 128 ); // radius + WRITE_BYTE( 128 ); // R + WRITE_BYTE( 255 ); // G + WRITE_BYTE( 128 ); // B + WRITE_BYTE( 1 ); // life * 10 + WRITE_COORD( 2 ); // decay + MESSAGE_END(); } -//========================================================= -// IdealPosition -//========================================================= -int CPitWorm::Level(float dz) +void CPitWorm::BeamEffect(TraceResult &tr) { - if (dz < PITWORM_LEVEL1_HEIGHT) - return PITWORM_LEVEL0; - - if (dz < PITWORM_LEVEL2_HEIGHT) - return PITWORM_LEVEL1; - - if (dz < PITWORM_LEVEL3_HEIGHT) - return PITWORM_LEVEL2; - - return PITWORM_LEVEL3; + CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); + if( pEntity != NULL && pEntity->pev->takedamage ) + { + ClearMultiDamage(); + pEntity->TraceAttack(pev, gSkillData.pwormDmgBeam, m_vecBeam, &tr, DMG_ENERGYBEAM); + ApplyMultiDamage(pev, pev); + } + else if ( tr.flFraction != 1.0f ) + { + UTIL_DecalTrace(&tr, DECAL_GUNSHOT1 + RANDOM_LONG(0,4)); + m_pBeam->DoSparks(tr.vecEndPos, tr.vecEndPos); + } } -//========================================================= -// IdealPosition -//========================================================= -const Vector& CPitWorm::IdealPosition(const int level) const +void CPitWorm::LockTopLevel() { - switch (level) - { - case PITWORM_LEVEL0: - return m_vecLevels[PITWORM_LEVEL0]; - case PITWORM_LEVEL1: - return m_vecLevels[PITWORM_LEVEL1]; - case PITWORM_LEVEL2: - return m_vecLevels[PITWORM_LEVEL2]; - case PITWORM_LEVEL3: - return m_vecLevels[PITWORM_LEVEL3]; - } - - return m_vecLevels[PITWORM_LEVEL3]; + if (m_iLevel == 3) + { + pev->health = pev->max_health; + m_iWasHit = 1; + m_iLevel = 2; + m_fTopLevelLocked = TRUE; + m_flTakeHitTime = gpGlobals->time + RANDOM_LONG(0,2); + m_posDesired.z = m_flLevels[2]; + } + else + { + m_fTopLevelLocked = TRUE; + } } -//========================================================= -// IdealPosition -//========================================================= -const Vector& CPitWorm::IdealPosition(const float dz) const +BOOL CPitWorm::ClawAttack() { - if (dz < PITWORM_LEVEL1_HEIGHT) - return m_vecLevels[PITWORM_LEVEL0]; + if (m_hEnemy == 0) + return FALSE; + if (pev->origin.z != m_posDesired.z) + return FALSE; + if ( m_flNextMeleeTime > gpGlobals->time ) + return FALSE; - if (dz < PITWORM_LEVEL2_HEIGHT) - return m_vecLevels[PITWORM_LEVEL1]; + float flDist = (pev->origin - m_hEnemy->pev->origin).Length2D(); + Vector targetAngle = UTIL_VecToAngles((m_posTarget - pev->origin).Normalize()); + float angleDiff = UTIL_AngleDiff(targetAngle.y, pev->angles.y); - if (dz < PITWORM_LEVEL3_HEIGHT) - return m_vecLevels[PITWORM_LEVEL2]; + if (!FVisible(m_posTarget)) + { + if (flDist < 600) + { + return 0; + } - return m_vecLevels[PITWORM_LEVEL3]; + BOOL shouldClaw = FALSE; + if (m_iLevel == 2) + { + if (angleDiff >= 30) + { + pev->sequence = LookupSequence("doorclaw1"); + m_flIdealHeadYaw = 0; + shouldClaw = TRUE; + } + } + else if (m_iLevel == 1) + { + if ( angleDiff <= -30.0 ) + { + pev->sequence = LookupSequence("doorclaw2"); + m_flIdealHeadYaw = 0; + shouldClaw = TRUE; + } + if ( angleDiff >= 30.0 ) + { + pev->sequence = LookupSequence("doorclaw3"); + m_flIdealHeadYaw = 0; + shouldClaw = TRUE; + } + } + + if (shouldClaw) + { + SwipeSound(); + m_fLockHeight = TRUE; + m_fLockYaw = TRUE; + m_fAttacking = TRUE; + return TRUE; + } + + return FALSE; + } + + m_fLockYaw = FALSE; + if (m_iLevel == 2) + { + if (angleDiff < 30) + { + if (flDist > 425 || angleDiff >= -50) + { + pev->sequence = LookupSequence("eyeblast"); + m_posBeam = m_posTarget; + m_vecBeam = m_vecTarget; + m_angleBeam = UTIL_VecToAngles(m_vecBeam); + } + else + { + pev->sequence = LookupSequence("attack"); + } + } + else + { + pev->sequence = LookupSequence("doorclaw1"); + m_flIdealHeadYaw = 0; + m_fLockYaw = TRUE; + } + } + else if (m_iLevel == 3) + { + if (flDist <= 425) + { + pev->sequence = RANDOM_LONG(0,1) ? LookupSequence("platclaw1") : LookupSequence("platclaw2"); + } + else + { + pev->sequence = LookupSequence("eyeblast"); + m_posBeam = m_posTarget; + m_vecBeam = m_vecTarget; + m_angleBeam = UTIL_VecToAngles(m_vecBeam); + } + } + else if (m_iLevel == 1) + { + if (angleDiff < 50) + { + if (angleDiff > -30) + { + if (flDist > 425) + { + pev->sequence = LookupSequence("eyeblast"); + m_posBeam = m_posTarget; + m_vecBeam = m_vecTarget; + m_angleBeam = UTIL_VecToAngles(m_vecBeam); + } + else + { + pev->sequence = LookupSequence("attacklow"); + } + } + else + { + pev->sequence = LookupSequence("doorclaw2"); + } + } + else + { + pev->sequence = LookupSequence("doorclaw3"); + m_flIdealHeadYaw = 0; + m_fLockYaw = TRUE; + } + } + if (pev->sequence == LookupSequence("eyeblast")) + { + BeamSound(); + } + else + { + SwipeSound(); + } + m_fAttacking = TRUE; + m_fLockHeight = TRUE; + return 1; } -//========================================================= -// IdealPosition -//========================================================= -const Vector& CPitWorm::IdealPosition(CBaseEntity* pEnemy) const +void CPitWorm::ShootBeam() { - return IdealPosition(pEnemy->pev->origin.z); + if ( m_hEnemy != 0 ) + { + if ( m_flHeadYaw > 0.0 ) + { + m_offsetBeam = 80; + m_flBeamDir = -1; + } + else + { + m_offsetBeam = -80; + m_flBeamDir = 1; + } + Vector vecEyePos, vecEyeAng; + GetAttachment(0, vecEyePos, vecEyeAng); + + m_vecBeam = (m_posBeam - vecEyePos).Normalize(); + m_angleBeam = UTIL_VecToAngles(m_vecBeam); + UTIL_MakeVectors(m_angleBeam); + m_vecBeam = gpGlobals->v_forward; + m_vecBeam.z = -m_vecBeam.z; + Vector vecEnd = m_vecBeam * m_offsetBeam + m_vecBeam * 1280 + vecEyePos; + + TraceResult tr; + UTIL_TraceLine(vecEyePos, vecEnd, dont_ignore_monsters, ENT(pev), &tr); + + m_pBeam = CBeam::BeamCreate("sprites/laserbeam.spr", 80); + if ( m_pBeam ) + { + m_pBeam->PointEntInit(tr.vecEndPos, entindex()); + m_pBeam->SetEndAttachment(1); + m_pBeam->SetColor(0,255,32); + m_pBeam->SetBrightness(128); + m_pBeam->SetWidth(32); + m_pBeam->pev->spawnflags |= SF_BEAM_SPARKSTART; + + BeamEffect(tr); + + m_pBeam->DoSparks(vecEyePos, vecEyePos); + m_flBeamExpireTime = gpGlobals->time + 0.9; + float beamYaw = m_flHeadYaw - m_flBeamDir * 25.0; + if ( beamYaw < -45.0 || beamYaw > 45.0 ) + { + m_flIdealHeadYaw += m_flBeamDir * 50; + } + + EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pShootSounds), VOL_NORM, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5)); + + EyeLight(vecEyePos); + + m_pSprite = CSprite::SpriteCreate("sprites/tele1.spr", vecEyePos, TRUE); + if ( m_pSprite ) + { + m_pSprite->SetTransparency(kRenderGlow, 0, 255, 0, 0, kRenderFxNoDissipation); + m_pSprite->SetAttachment(edict(), 1); + m_pSprite->SetScale(0.75); + m_pSprite->pev->framerate = 10; + m_pSprite->TurnOn(); + } + } + } } -#define clamp( val, min, max ) ( ((val) > (max)) ? (max) : ( ((val) < (min)) ? (min) : (val) ) ) - -//========================================================= -// UpdateBodyControllers -//========================================================= -void CPitWorm::UpdateBodyControllers(void) +void CPitWorm::StrafeBeam() { - if (m_hEnemy == 0 || m_fBeamOn) - return; + m_offsetBeam += m_flBeamDir * 20; - ASSERT(m_hEnemy); + Vector vecEyePos, vecEyeAng; + GetAttachment(0, vecEyePos, vecEyeAng); - Vector vecGoal = m_hEnemy->EyePosition(); - Vector vecEye = EyePosition(); + m_vecBeam = (m_posBeam - vecEyePos).Normalize(); + m_angleBeam = UTIL_VecToAngles(m_vecBeam); + UTIL_MakeVectors(m_angleBeam); + m_vecBeam = gpGlobals->v_forward; + m_vecBeam.z = -m_vecBeam.z; - Vector target = (vecGoal - vecEye).Normalize(); - Vector angles = UTIL_VecToAngles(target); - float yaw = UTIL_VecToYaw(target); - float pitch = angles.x; - float targetYaw = yaw - m_flInitialYaw; + Vector vecEnd = m_vecBeam * m_offsetBeam + m_vecBeam * 1280 + vecEyePos; + TraceResult tr; + UTIL_TraceLine(vecEyePos, vecEnd, dont_ignore_monsters, ENT(pev), &tr); - if (pitch < -180) - pitch += 360; + m_pBeam->SetStartPos(tr.vecEndPos); + BeamEffect(tr); - if (pitch > 180) - pitch -= 360; - - float bodyYaw = clamp(targetYaw, PITWORM_BODY_YAW_MIN, PITWORM_BODY_YAW_MAX); - - - float targetBody = (fabs(targetYaw) * (bodyYaw - 5)) / 90; - - // Convert value to clamp it between min / max value of bone controller. - float eyePitch = pitch; - float eyeYaw = (targetBody * PITWORM_EYE_YAW_MAX) / PITWORM_BODY_YAW_MAX; - - - // Clamp those values (ensure they stay between min / max). - eyePitch = clamp(eyePitch, PITWORM_EYE_PITCH_MIN, PITWORM_EYE_PITCH_MAX); - eyeYaw = clamp(eyeYaw, PITWORM_EYE_YAW_MIN, PITWORM_EYE_YAW_MAX); - - // Update body yaw controller value. - SetBoneController(PITWORM_CONTROLLER_BODY_YAW, bodyYaw); - - // Update eye pitch controller value. - SetBoneController(PITWORM_CONTROLLER_EYE_PITCH, -eyePitch); - - // Update eye yaw contoller value. - SetBoneController(PITWORM_CONTROLLER_EYE_YAW, eyeYaw); + EyeLight(vecEyePos); } -//========================================================= -// CreateBeam -//========================================================= -void CPitWorm::CreateBeam(const Vector& src, const Vector& target, int width) +void CPitWorm::ChangeLevel() { - pev->skin = 0; + float currentZ = pev->origin.z; + float desiredZ = m_posDesired.z; + if (currentZ > desiredZ) + { + pev->origin.z -= m_flLevelSpeed; - m_pBeam = CBeam::BeamCreate("sprites/gworm_beam_02.spr", width); - if (m_pBeam) - { - m_pBeam->PointsInit(src, target); - m_pBeam->SetBrightness(200); - m_pBeam->SetColor(0, 255, 0); - m_pBeam->SetNoise(0); - m_pBeam->SetFrame(0); - m_pBeam->SetScrollRate(10); - m_pBeam->RelinkBeam(); + if (pev->origin.z < desiredZ) + pev->origin.z = desiredZ; + } + else if (currentZ < desiredZ) + { + pev->origin.z += m_flLevelSpeed; - m_fBeamOn = TRUE; - } + if (pev->origin.z > desiredZ) + pev->origin.z = desiredZ; + } + + if (m_flIdealTorsoYaw != m_flTorsoYaw) + { + if (m_flIdealTorsoYaw < m_flTorsoYaw) + { + m_flTorsoYaw -= 5.0; + if (m_flTorsoYaw < m_flIdealTorsoYaw) + m_flTorsoYaw = m_flIdealTorsoYaw; + } + else if (m_flIdealTorsoYaw > m_flTorsoYaw) + { + m_flTorsoYaw += 5; + if (m_flTorsoYaw > m_flIdealTorsoYaw) + m_flTorsoYaw = m_flIdealTorsoYaw; + } + SetBoneController(PITWORM_CONTROLLER_BODY_YAW, m_flTorsoYaw); + } + + if (m_flIdealHeadYaw != m_flHeadYaw) + { + if (m_flIdealHeadYaw < m_flHeadYaw) + { + m_flHeadYaw -= 5.0; + if (m_flHeadYaw < m_flIdealHeadYaw) + m_flHeadYaw = m_flIdealHeadYaw; + } + else if (m_flIdealHeadYaw > m_flHeadYaw) + { + m_flHeadYaw += 5; + if (m_flHeadYaw > m_flIdealHeadYaw) + m_flHeadYaw = m_flIdealHeadYaw; + } + SetBoneController(PITWORM_CONTROLLER_EYE_YAW, m_flHeadYaw); + } + + if (m_flIdealHeadPitch != m_flHeadPitch) + { + if (m_flIdealHeadPitch < m_flHeadPitch) + { + m_flHeadPitch -= 5.0; + if (m_flHeadPitch < m_flIdealHeadPitch) + m_flHeadPitch = m_flIdealHeadPitch; + } + else if (m_flIdealHeadPitch > m_flHeadPitch) + { + m_flHeadPitch += 5; + if (m_flHeadPitch > m_flIdealHeadPitch) + m_flHeadPitch = m_flIdealHeadPitch; + } + SetBoneController(PITWORM_CONTROLLER_EYE_PITCH, m_flHeadPitch); + } } -//========================================================= -// DestroyBeam -//========================================================= -void CPitWorm::DestroyBeam(void) +void CPitWorm::TrackEnemy() { - if (m_pBeam) - { - UTIL_Remove(m_pBeam); - m_pBeam = NULL; + Vector vecEyePos, vecEyeAng; + GetAttachment(0, vecEyePos, vecEyeAng); - m_fBeamOn = FALSE; - m_vecEmemyPos = g_vecZero; - m_flPlayerDamage = 0; - m_iLaserHitTimes = 0; - } -} - -//========================================================= -// UpdateBeam -//========================================================= -void CPitWorm::UpdateBeam(const Vector& src, const Vector& target) -{ - if (m_pBeam) - { - m_pBeam->SetStartPos(src); - m_pBeam->SetEndPos(target); - m_pBeam->SetColor(0, 255, 0); - m_pBeam->SetBrightness(200); - m_pBeam->RelinkBeam(); - } -} - -//========================================================= -// SetupBeamPoints -//========================================================= -void CPitWorm::SetupBeamPoints(CBaseEntity* pEnemy, Vector* vecleft, Vector* vecRight) -{ - Vector forward, right, up; - - if(m_vecEmemyPos == g_vecZero) - m_vecEmemyPos = pEnemy->Center() + Vector(-10,0,25); - - if (pEnemy->IsPlayer()) - UTIL_MakeAimVectors(pEnemy->pev->v_angle); - else - UTIL_MakeAimVectors(pEnemy->pev->angles); - - forward = gpGlobals->v_forward; - right = gpGlobals->v_right; - up = gpGlobals->v_up; - - *vecleft = m_vecEmemyPos + (right * -16); - *vecRight = m_vecEmemyPos + (right * 32); -} - -//========================================================= -// UpdateBeamPoints -//========================================================= -void CPitWorm::UpdateBeamPoints(CBaseEntity* pEnemy, Vector* target) -{ - Vector left, right; - Vector dir; - float delta; - - delta = 1.0f / (PITWORM_EYEBLAST_DURATION * 2); // 0.24 approximatly. (248 miliseconds) - - // Update beam yaw. - m_flBeamYaw += delta; - - // Convert to distance to make the correct interpolation. - float flDist = (6.25 * m_flBeamYaw) / PITWORM_EYEBLAST_DURATION; - - SetupBeamPoints(pEnemy, &left, &right); - - // Direction from right to left. - dir = (left - right).Normalize(); - - // This is the result representing the next beam target - // position along the player's left and right computed beam - // positions. - *target = right + (dir * (flDist*1.2)); -} - -//========================================================= -// CreateGlow -//========================================================= -void CPitWorm::CreateGlow(void) -{ - m_pEyeGlow = CSprite::SpriteCreate("sprites/glow_grn.spr", pev->origin, TRUE); - m_pEyeGlow->SetTransparency(kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation); - m_pEyeGlow->SetAttachment(edict(), 1); - m_pEyeGlow->SetScale(2.0f); -} - -//========================================================= -// DestroyGlow -//========================================================= -void CPitWorm::DestroyGlow(void) -{ - if (m_pEyeGlow) - { - UTIL_Remove(m_pEyeGlow); - m_pEyeGlow = NULL; - } -} - -//========================================================= -// EyeOn -//========================================================= -void CPitWorm::EyeOn(int level) -{ - m_eyeBrightness = level; -} - -//========================================================= -// EyeOff -//========================================================= -void CPitWorm::EyeOff(void) -{ - m_eyeBrightness = 0; -} - -//========================================================= -// EyeUpdate -//========================================================= -void CPitWorm::EyeUpdate(void) -{ - if (m_pEyeGlow) - { - m_pEyeGlow->pev->renderamt = UTIL_Approach(m_eyeBrightness, m_pEyeGlow->pev->renderamt, 100); - if (m_pEyeGlow->pev->renderamt == 0) - m_pEyeGlow->pev->effects |= EF_NODRAW; - else - m_pEyeGlow->pev->effects &= ~EF_NODRAW; - - UTIL_SetOrigin(m_pEyeGlow->pev, pev->origin); - } + Vector vec = (m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs) - Vector(pev->origin.x, pev->origin.y, vecEyePos.z); + Vector vecDir = UTIL_VecToAngles(vec); + float angleDiff = UTIL_AngleDiff(vecDir.x, pev->angles.x); + if (angleDiff < PITWORM_EYE_PITCH_MIN) + { + angleDiff = PITWORM_EYE_PITCH_MIN; + } + else if (angleDiff > PITWORM_EYE_PITCH_MAX) + { + angleDiff = PITWORM_EYE_PITCH_MAX; + } + m_flIdealHeadPitch = angleDiff; + + float targetYaw = UTIL_VecToYaw(m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - vecEyePos) - pev->angles.y; + if (targetYaw > 180) + { + targetYaw -= 360; + } + else if (targetYaw < -180) + { + targetYaw += 360; + } + if (!m_fLockYaw) + { + if (targetYaw < 0) + { + const float minYaw = (m_iLevel == 1) ? -30 : -50; + if (targetYaw <= minYaw) + targetYaw = minYaw; + } + else + { + const float maxYaw = (m_iLevel == 2) ? 30 :50; + if (targetYaw > maxYaw) + targetYaw = maxYaw; + } + m_flIdealTorsoYaw = targetYaw; + } + float torsoYawDiff = m_flTorsoYaw - targetYaw; + if (torsoYawDiff > 0) + { + if (torsoYawDiff > PITWORM_EYE_YAW_MAX) + { + torsoYawDiff = PITWORM_EYE_YAW_MAX; + } + else if (torsoYawDiff < PITWORM_EYE_YAW_MIN) + { + torsoYawDiff = PITWORM_EYE_YAW_MIN; + } + } + if (!m_fAttacking || m_pBeam != 0) + { + m_flIdealHeadYaw = torsoYawDiff; + } + + if (!m_fLockHeight) + { + if (m_hEnemy->pev->origin.z <= m_flTargetLevels[1]) + { + m_iLevel = 0; + } + else if (m_hEnemy->pev->origin.z <= m_flTargetLevels[2]) + { + m_iLevel = 1; + } + else if (m_fTopLevelLocked || m_hEnemy->pev->origin.z <= m_flTargetLevels[3]) + { + m_iLevel = 2; + } + else + { + m_iLevel = 3; + } + m_posDesired.z = m_flLevels[m_iLevel]; + } }