From aa426660c2f5f9a00a3a57d96dfa5f832f33a1e6 Mon Sep 17 00:00:00 2001 From: Roman Chistokhodov Date: Tue, 30 Jul 2019 23:38:45 +0300 Subject: [PATCH] Update pitdrone --- dlls/gearbox/pitdrone.cpp | 846 +++++++------------------------------- 1 file changed, 159 insertions(+), 687 deletions(-) diff --git a/dlls/gearbox/pitdrone.cpp b/dlls/gearbox/pitdrone.cpp index d6629f46..c95ac2a4 100644 --- a/dlls/gearbox/pitdrone.cpp +++ b/dlls/gearbox/pitdrone.cpp @@ -1,5 +1,3 @@ -#if 0 - /*** * * Copyright (c) 1996-2001, Valve LLC. All rights reserved. @@ -8,15 +6,12 @@ * 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. +* 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. * ****/ -//========================================================= -// pitdrone -//========================================================= #include "extdll.h" #include "util.h" @@ -28,605 +23,42 @@ #include "decals.h" #include "soundent.h" #include "game.h" -#include "bullsquid.h" - -extern int iSquidSpitSprite; - -#define PITDRONE_SPRINT_DIST 256 // how close the squid has to get before starting to sprint and refusing to swerve - -#define PITDRONE_TOLERANCE_MELEE1_RANGE 85 -#define PITDRONE_TOLERANCE_MELEE2_RANGE 85 - -#define PITDRONE_TOLERANCE_MELEE1_DOT 0.7 -#define PITDRONE_TOLERANCE_MELEE2_DOT 0.7 - -#define PITDRONE_MELEE_ATTACK_RADIUS 70 - -//========================================================= -// Monster's Anim Events Go Here -//========================================================= - -#define PITDRONE_AE_THROW ( 1 ) -#define PITDRONE_AE_SLASH_BOTH ( 2 ) -#define PITDRONE_AE_SLASH_SINGLE ( 4 ) - -//========================================================= -// CPitdrone -//========================================================= -class CPitdrone : public CBullsquid -{ -public: - - void Spawn(void); - void Precache(void); - - void KeyValue(KeyValueData *pkvd); - - int Classify(void); - void HandleAnimEvent(MonsterEvent_t *pEvent); - void IdleSound(void); - void PainSound(void); - void DeathSound(void); - void AlertSound(void); - void AttackSound(void); - void StartTask(Task_t *pTask); - - BOOL CheckMeleeAttack1(float flDot, float flDist); - BOOL CheckMeleeAttack2(float flDot, float flDist); - BOOL CheckRangeAttack1(float flDot, float flDist); - void RunAI(void); - - int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); - int IRelationship(CBaseEntity *pTarget); - int IgnoreConditions(void); - - int Save(CSave &save); - int Restore(CRestore &restore); - static TYPEDESCRIPTION m_SaveData[]; - -protected: - - int m_nAmmoCount; - int m_fRightSlash; -}; - -LINK_ENTITY_TO_CLASS(monster_pitdrone, CPitdrone); - -TYPEDESCRIPTION CPitdrone::m_SaveData[] = -{ - DEFINE_FIELD(CPitdrone, m_nAmmoCount, FIELD_INTEGER), - DEFINE_FIELD(CPitdrone, m_fRightSlash, FIELD_BOOLEAN), -}; - -IMPLEMENT_SAVERESTORE(CPitdrone, CBullsquid); - -void CPitdrone::KeyValue(KeyValueData *pkvd) -{ - if (FStrEq(pkvd->szKeyName, "initammo")) - { - m_nAmmoCount = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBullsquid::KeyValue(pkvd); -} - - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CPitdrone::Classify(void) -{ - return CLASS_ALIEN_MONSTER; -} - -//========================================================= -// IgnoreConditions -//========================================================= -int CPitdrone::IgnoreConditions(void) -{ - return CBaseMonster::IgnoreConditions(); -} - -//========================================================= -// IRelationship - overridden for gonome -//========================================================= -int CPitdrone::IRelationship(CBaseEntity *pTarget) -{ - return CBaseMonster::IRelationship(pTarget); -} - -//========================================================= -// TakeDamage - overridden for gonome so we can keep track -// of how much time has passed since it was last injured -//========================================================= -int CPitdrone::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) -{ - float flDist; - Vector vecApex; - - // if the squid is running, has an enemy, was hurt by the enemy, hasn't been hurt in the last 3 seconds, and isn't too close to the enemy, - // it will swerve. (whew). - if (m_hEnemy != NULL && IsMoving() && pevAttacker == m_hEnemy->pev && gpGlobals->time - m_flLastHurtTime > 3) - { - flDist = (pev->origin - m_hEnemy->pev->origin).Length2D(); - - if (flDist > PITDRONE_SPRINT_DIST) - { - flDist = (pev->origin - m_Route[m_iRouteIndex].vecLocation).Length2D();// reusing flDist. - - if (FTriangulate(pev->origin, m_Route[m_iRouteIndex].vecLocation, flDist * 0.5, m_hEnemy, &vecApex)) - { - InsertWaypoint(vecApex, bits_MF_TO_DETOUR | bits_MF_DONT_SIMPLIFY); - } - } - } - - return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); -} - - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CPitdrone::CheckRangeAttack1(float flDot, float flDist) -{ - if (IsMoving() && flDist >= 512) - { - // squid will far too far behind if he stops running to spit at this distance from the enemy. - return FALSE; - } - - if (flDist > 64 && flDist <= 784 && flDot >= 0.5 && gpGlobals->time >= m_flNextSpitTime) - { - if (m_hEnemy != NULL) - { - if (fabs(pev->origin.z - m_hEnemy->pev->origin.z) > 256) - { - // don't try to spit at someone up really high or down really low. - return FALSE; - } - } - - if (IsMoving()) - { - // don't spit again for a long time, resume chasing enemy. - m_flNextSpitTime = gpGlobals->time + 5; - } - else - { - // not moving, so spit again pretty soon. - m_flNextSpitTime = gpGlobals->time + 0.5; - } - - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckMeleeAttack1 - pitdrone is a big guy, so has a longer -// melee range than most monsters. This is the tailwhip attack -//========================================================= -BOOL CPitdrone::CheckMeleeAttack1(float flDot, float flDist) -{ - - if (m_hEnemy->pev->health <= gSkillData.pitdroneDmgWhip && - flDist <= PITDRONE_TOLERANCE_MELEE1_RANGE && - flDot >= PITDRONE_TOLERANCE_MELEE1_DOT) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// CheckMeleeAttack2 - pitdrone is a big guy, so has a longer -// melee range than most monsters. This is the bite attack. -// this attack will not be performed if the tailwhip attack -// is valid. -//========================================================= -BOOL CPitdrone::CheckMeleeAttack2(float flDot, float flDist) -{ - if (flDist <= PITDRONE_TOLERANCE_MELEE2_RANGE && - flDot >= PITDRONE_TOLERANCE_MELEE2_DOT && - !HasConditions(bits_COND_CAN_MELEE_ATTACK1)) - { - return TRUE; - } - - return FALSE; -} - - -//========================================================= -// IdleSound -//========================================================= -#define PITDRONE_ATTN_IDLE (float)1.5 -void CPitdrone::IdleSound(void) -{ - switch (RANDOM_LONG(0, 2)) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_idle1.wav", 1, PITDRONE_ATTN_IDLE); - break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_idle2.wav", 1, PITDRONE_ATTN_IDLE); - break; - case 2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_idle3.wav", 1, PITDRONE_ATTN_IDLE); - break; - } -} - -//========================================================= -// PainSound -//========================================================= -void CPitdrone::PainSound(void) -{ - int iPitch = RANDOM_LONG(85, 120); - - switch (RANDOM_LONG(0, 3)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_pain1.wav", 1, ATTN_NORM, 0, iPitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_pain2.wav", 1, ATTN_NORM, 0, iPitch); - break; - case 2: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_pain3.wav", 1, ATTN_NORM, 0, iPitch); - break; - case 3: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_pain4.wav", 1, ATTN_NORM, 0, iPitch); - break; - } -} - -//========================================================= -// AlertSound -//========================================================= -void CPitdrone::AlertSound(void) -{ - int iPitch = RANDOM_LONG(140, 160); - - switch (RANDOM_LONG(0, 2)) - { - case 0: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_alert1.wav", 1, ATTN_NORM, 0, iPitch); - break; - case 1: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_alert2.wav", 1, ATTN_NORM, 0, iPitch); - break; - case 2: - EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "pitdrone/pitdrone_alert3.wav", 1, ATTN_NORM, 0, iPitch); - break; - } -} - - - -//========================================================= -// HandleAnimEvent - catches the monster-specific messages -// that occur when tagged animation frames are played. -//========================================================= -void CPitdrone::HandleAnimEvent(MonsterEvent_t *pEvent) -{ - switch (pEvent->event) - { - - case PITDRONE_AE_THROW: - { - Vector vecSpitOffset; - Vector vecSpitDir; - - UTIL_MakeVectors(pev->angles); - - // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. - // we should be able to read the position of bones at runtime for this info. - - - Vector vecArmPos, vecArmAng; - GetAttachment(0, vecArmPos, vecArmAng); - - //vecSpitOffset = (gpGlobals->v_right * 8 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 23); - //vecSpitOffset = (pev->origin + vecSpitOffset); - vecSpitOffset = vecArmPos; - vecSpitDir = ((m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs) - vecSpitOffset).Normalize(); - vecSpitDir.x += RANDOM_FLOAT(-0.05, 0.05); - vecSpitDir.y += RANDOM_FLOAT(-0.05, 0.05); - vecSpitDir.z += RANDOM_FLOAT(-0.05, 0); +/* + * In Opposing Force pitdrone spawned via monstermaker did not have spikes + * That's probably a bug, because number of spikes is set in level editor, + * so spawned pitdrones always had 0 spikes. + * Having no spikes after spawn also prevented spike reloading. + * Those who want to keep original Opposing Force behavior can set this constant to zero. + */ +#define FEATURE_PITDRONE_SPAWN_WITH_SPIKES 1 - // do stuff for this event. - AttackSound(); +// Disable this feature if you don't want to include spike_trail.spr in your mod +#define FEATURE_PITDRONE_SPIKE_TRAIL 1 - // spew the spittle temporary ents. - MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpitOffset); - WRITE_BYTE(TE_SPRITE_SPRAY); - WRITE_COORD(vecSpitOffset.x); // pos - WRITE_COORD(vecSpitOffset.y); - WRITE_COORD(vecSpitOffset.z); - WRITE_COORD(vecSpitDir.x); // dir - WRITE_COORD(vecSpitDir.y); - WRITE_COORD(vecSpitDir.z); - WRITE_SHORT(iSquidSpitSprite); // model - WRITE_BYTE(15); // count - WRITE_BYTE(210); // speed - WRITE_BYTE(25); // noise ( client will divide by 100 ) - MESSAGE_END(); - - CSquidSpit::Shoot(pev, vecSpitOffset, vecSpitDir * 1200); // Default: 900 - } - break; - - case PITDRONE_AE_SLASH_SINGLE: - { - CBaseEntity *pHurt = CheckTraceHullAttack(PITDRONE_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneSlash, DMG_CLUB); - if (pHurt) - { - // Left slash - if (!m_fRightSlash) - { - pHurt->pev->punchangle.z = -20; - pHurt->pev->punchangle.x = 20; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * -100; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 20; - } - else // Right slash - { - pHurt->pev->punchangle.z = 20; - pHurt->pev->punchangle.x = 20; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_right * 100; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 20; - } - } - - m_fRightSlash = !m_fRightSlash; - } - break; - - case PITDRONE_AE_SLASH_BOTH: - { - CBaseEntity *pHurt = CheckTraceHullAttack(PITDRONE_MELEE_ATTACK_RADIUS, gSkillData.gonomeDmgOneSlash, DMG_CLUB); - if (pHurt) - { - pHurt->pev->punchangle.x = 20; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * -150; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 20; - } - } - break; - - default: - CBaseMonster::HandleAnimEvent(pEvent); - } -} - -//========================================================= -// Spawn -//========================================================= -void CPitdrone::Spawn() -{ - Precache(); - - SET_MODEL(ENT(pev), "models/pit_drone.mdl"); - UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX); - - pev->solid = SOLID_SLIDEBOX; - pev->movetype = MOVETYPE_STEP; - m_bloodColor = BLOOD_COLOR_GREEN; - pev->effects = 0; - pev->health = gSkillData.pitdroneHealth; - m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) - m_MonsterState = MONSTERSTATE_NONE; - - m_fCanThreatDisplay = TRUE; - m_flNextSpitTime = gpGlobals->time; - - m_fRightSlash = FALSE; - - MonsterInit(); -} - -//========================================================= -// Precache - precaches all resources this monster needs -//========================================================= -void CPitdrone::Precache() -{ - PRECACHE_MODEL("models/pit_drone.mdl"); - - PRECACHE_MODEL("sprites/bigspit.spr");// spit projectile. - - iSquidSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle. - - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event - - PRECACHE_SOUND("pitdrone/pit_drone_attack_spike1.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_attack_spike2.wav"); - - PRECACHE_SOUND("pitdrone/pit_drone_communicate1.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_communicate2.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_communicate3.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_communicate4.wav"); - - PRECACHE_SOUND("pitdrone/pit_drone_die1.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_die2.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_die3.wav"); - - PRECACHE_SOUND("pitdrone/pit_drone_eat.wav"); - - PRECACHE_SOUND("pitdrone/pit_drone_hunt1.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_hunt2.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_hunt3.wav"); - - PRECACHE_SOUND("pitdrone/pit_drone_idle1.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_idle2.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_idle3.wav"); - - PRECACHE_SOUND("bullchicken/pit_drone_melee_attack1.wav"); - PRECACHE_SOUND("bullchicken/pit_drone_melee_attack2.wav"); - - PRECACHE_SOUND("pitdrone/pit_drone_pain1.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_pain2.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_pain3.wav"); - PRECACHE_SOUND("pitdrone/pit_drone_pain4.wav"); - - PRECACHE_SOUND("bullchicken/bc_acid1.wav"); - - PRECACHE_SOUND("bullchicken/bc_bite2.wav"); - PRECACHE_SOUND("bullchicken/bc_bite3.wav"); - - PRECACHE_SOUND("bullchicken/bc_spithit1.wav"); - PRECACHE_SOUND("bullchicken/bc_spithit2.wav"); -} - -//========================================================= -// DeathSound -//========================================================= -void CPitdrone::DeathSound(void) -{ - switch (RANDOM_LONG(0, 2)) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitdrone/pit_drone_die1.wav", 1, ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitdrone/pit_drone_die2.wav", 1, ATTN_NORM); - break; - case 2: - EMIT_SOUND(ENT(pev), CHAN_VOICE, "pitdrone/pit_drone_die3.wav", 1, ATTN_NORM); - break; - } -} - -//========================================================= -// AttackSound -//========================================================= -void CPitdrone::AttackSound(void) -{ - switch (RANDOM_LONG(0, 1)) - { - case 0: - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "pitdrone/pit_drone_attack_spike1.wav", 1, ATTN_NORM); - break; - case 1: - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "pitdrone/pit_drone_attack_spike2.wav", 1, ATTN_NORM); - break; - } -} - -//======================================================== -// RunAI - overridden for pitdrone because there are things -// that need to be checked every think. -//======================================================== -void CPitdrone::RunAI(void) -{ - // first, do base class stuff - CBaseMonster::RunAI(); - - if (m_hEnemy != NULL && m_Activity == ACT_RUN) - { - // chasing enemy. Sprint for last bit - if ((pev->origin - m_hEnemy->pev->origin).Length2D() < PITDRONE_SPRINT_DIST) - { - pev->framerate = 1.25; - } - } - -} - - -//========================================================= -// Start task - selects the correct activity and performs -// any necessary calculations to start the next task on the -// schedule. OVERRIDDEN for pitdrone because it needs to -// know explicitly when the last attempt to chase the enemy -// failed, since that impacts its attack choices. -//========================================================= -void CPitdrone::StartTask(Task_t *pTask) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch (pTask->iTask) - { - case TASK_MELEE_ATTACK2: - CBaseMonster::StartTask(pTask); - break; - - default: - CBullsquid::StartTask(pTask); - break; - - } -} -#else - -//------------------------------------------------- -// Opposing Forces monster Pit Drone -// Remaking by Demiurge aka Z-Zero SYSTEMS 2004 -// All rights by GEARBOX -// -// FGD monster_pitdrone -// [ -// initammo(string) : "Initial Ammo" : "6" -// ] -// -//------------------------------------------------- - -#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "monsters.h" -#include "schedule.h" -#include "nodes.h" -#include "effects.h" -#include "decals.h" -#include "soundent.h" -#include "game.h" -#include "weapons.h" - -int iPitDroneSpitSprite; +#if FEATURE_PITDRONE_SPIKE_TRAIL +int iSpikeTrail; +#endif +int iPitdroneSpitSprite; //========================================================= // CPitDrone's spit projectile //========================================================= -class CPitDroneSpit : public CBaseMonster +class CPitdroneSpike : public CBaseEntity { +public: void Spawn(void); void Precache(void); - int Classify(void); - void EXPORT Touch(CBaseEntity *pOther); - - Vector m_vecForward; - -public: - static CPitDroneSpit *SpitCreate(void); + void EXPORT SpikeTouch(CBaseEntity *pOther); + void EXPORT StartTrail(); + static void Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, Vector vecAngles); }; -LINK_ENTITY_TO_CLASS(pitdronespit, CPitDroneSpit) - -CPitDroneSpit *CPitDroneSpit::SpitCreate(void) -{ - // Create a new entity with CShock private data - CPitDroneSpit *pSpit = GetClassPtr((CPitDroneSpit *)NULL); - pSpit->pev->classname = MAKE_STRING("pitdronespit"); - pSpit->Spawn(); - - return pSpit; -} - -int CPitDroneSpit::Classify(void) -{ - return CLASS_ALIEN_BIOWEAPON; -} +LINK_ENTITY_TO_CLASS(pitdronespike, CPitdroneSpike) -void CPitDroneSpit::Spawn(void) +void CPitdroneSpike::Spawn(void) { pev->movetype = MOVETYPE_FLY; - pev->classname = MAKE_STRING("pitdronespit"); + pev->classname = MAKE_STRING("pitdronespike"); pev->solid = SOLID_BBOX; pev->rendermode = kRenderTransAlpha; @@ -636,21 +68,21 @@ void CPitDroneSpit::Spawn(void) pev->frame = 0; pev->scale = 0.5; - UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); - UTIL_SetOrigin(pev, pev->origin); - UTIL_MakeAimVectors(pev->angles); - m_vecForward = gpGlobals->v_forward; - SetTouch(&CPitDroneSpit::Touch); + UTIL_SetSize(pev, Vector(-4, -4, -4), Vector(4, 4, 4)); } -void CPitDroneSpit::Precache(void) +void CPitdroneSpike::Precache(void) { + PRECACHE_MODEL("models/pit_drone_spike.mdl");// spit projectile PRECACHE_SOUND("weapons/xbow_hitbod1.wav"); PRECACHE_SOUND("weapons/xbow_hitbod2.wav"); PRECACHE_SOUND("weapons/xbow_hit1.wav"); +#if FEATURE_PITDRONE_SPIKE_TRAIL + iSpikeTrail = PRECACHE_MODEL("sprites/spike_trail.spr"); +#endif } -void CPitDroneSpit::Touch(CBaseEntity *pOther) +void CPitdroneSpike::SpikeTouch(CBaseEntity *pOther) { TraceResult tr; int iPitch; @@ -689,11 +121,42 @@ void CPitDroneSpit::Touch(CBaseEntity *pOther) EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, iPitch); else EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, iPitch); - + SetThink( &CBaseEntity::SUB_Remove ); pev->nextthink = gpGlobals->time; } +} +void CPitdroneSpike::StartTrail() +{ +#if FEATURE_PITDRONE_SPIKE_TRAIL + MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); + WRITE_BYTE( TE_BEAMFOLLOW ); + WRITE_SHORT( entindex() ); + WRITE_SHORT( iSpikeTrail ); // model + WRITE_BYTE(2); // life + WRITE_BYTE(1); // width + WRITE_BYTE(197); // r + WRITE_BYTE(194); // g + WRITE_BYTE(11); // b + WRITE_BYTE(192); //brigtness + MESSAGE_END(); +#endif + SetTouch(&CPitdroneSpike::SpikeTouch); +} + +void CPitdroneSpike::Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, Vector vecAngles) +{ + CPitdroneSpike *pSpit = GetClassPtr( (CPitdroneSpike *)NULL ); + pSpit->Spawn(); + + UTIL_SetOrigin( pSpit->pev, vecStart ); + pSpit->pev->velocity = vecVelocity; + pSpit->pev->angles = vecAngles; + pSpit->pev->owner = ENT( pevOwner ); + + pSpit->SetThink(&CPitdroneSpike::StartTrail); + pSpit->pev->nextthink = gpGlobals->time + 0.1; } // @@ -729,7 +192,7 @@ enum //========================================================= enum { - TASK_PDRONE_HOPTURN = LAST_COMMON_SCHEDULE + 1 + TASK_PDRONE_HOPTURN = LAST_COMMON_TASK + 1 }; //========================================================= @@ -744,9 +207,9 @@ enum #define PIT_DRONE_AE_THROW ( 6 ) #define PIT_DRONE_AE_RELOAD ( 7 ) -class CPitDrone : public CBaseMonster +class CPitdrone : public CBaseMonster { - +public: void Spawn(void); void Precache(void); void HandleAnimEvent(MonsterEvent_t *pEvent); @@ -774,10 +237,10 @@ class CPitDrone : public CBaseMonster void GibMonster(); CUSTOM_SCHEDULES + float m_flLastHurtTime; float m_flNextSpitTime;// last time the PitDrone used the spit attack. float m_flNextFlinch; - int spikes; - BOOL canReloadSpikes; + int m_iInitialAmmo; bool shouldAttackWithLeftClaw; static const char *pIdleSounds[]; @@ -791,23 +254,22 @@ class CPitDrone : public CBaseMonster static TYPEDESCRIPTION m_SaveData[]; }; -LINK_ENTITY_TO_CLASS(monster_pitdrone, CPitDrone) +LINK_ENTITY_TO_CLASS(monster_pitdrone, CPitdrone) -TYPEDESCRIPTION CPitDrone::m_SaveData[] = +TYPEDESCRIPTION CPitdrone::m_SaveData[] = { - DEFINE_FIELD(CPitDrone, spikes, FIELD_INTEGER), - DEFINE_FIELD(CPitDrone, canReloadSpikes, FIELD_BOOLEAN), - DEFINE_FIELD(CPitDrone, m_flNextSpitTime, FIELD_TIME), + DEFINE_FIELD(CPitdrone, m_iInitialAmmo, FIELD_INTEGER), + DEFINE_FIELD(CPitdrone, m_flLastHurtTime, FIELD_TIME), + DEFINE_FIELD(CPitdrone, m_flNextSpitTime, FIELD_TIME), }; -IMPLEMENT_SAVERESTORE(CPitDrone, CBaseMonster) +IMPLEMENT_SAVERESTORE(CPitdrone, CBaseMonster) -void CPitDrone::KeyValue(KeyValueData *pkvd) +void CPitdrone::KeyValue(KeyValueData *pkvd) { - if (FStrEq(pkvd->szKeyName, "initammo")) { - spikes = atoi(pkvd->szValue); + m_iInitialAmmo = atoi(pkvd->szValue); pkvd->fHandled = TRUE; } else @@ -817,7 +279,7 @@ void CPitDrone::KeyValue(KeyValueData *pkvd) //========================================================= // IgnoreConditions //========================================================= -int CPitDrone::IgnoreConditions(void) +int CPitdrone::IgnoreConditions(void) { int iIgnore = CBaseMonster::IgnoreConditions(); @@ -837,13 +299,13 @@ int CPitDrone::IgnoreConditions(void) } -const char *CPitDrone::pAttackMissSounds[] = +const char *CPitdrone::pAttackMissSounds[] = { "zombie/claw_miss1.wav", "zombie/claw_miss2.wav", }; -const char *CPitDrone::pIdleSounds[] = +const char *CPitdrone::pIdleSounds[] = { "pitdrone/pit_drone_idle1.wav", "pitdrone/pit_drone_idle2.wav", @@ -851,14 +313,14 @@ const char *CPitDrone::pIdleSounds[] = }; -const char *CPitDrone::pAlertSounds[] = +const char *CPitdrone::pAlertSounds[] = { "pitdrone/pit_drone_alert1.wav", "pitdrone/pit_drone_alert2.wav", "pitdrone/pit_drone_alert3.wav", }; -const char *CPitDrone::pPainSounds[] = +const char *CPitdrone::pPainSounds[] = { "pitdrone/pit_drone_pain1.wav", "pitdrone/pit_drone_pain2.wav", @@ -866,7 +328,7 @@ const char *CPitDrone::pPainSounds[] = "pitdrone/pit_drone_pain4.wav", }; -const char *CPitDrone::pDieSounds[] = +const char *CPitdrone::pDieSounds[] = { "pitdrone/pit_drone_die1.wav", "pitdrone/pit_drone_die2.wav", @@ -877,7 +339,7 @@ const char *CPitDrone::pDieSounds[] = // TakeDamage - overridden for gonome so we can keep track // of how much time has passed since it was last injured //========================================================= -int CPitDrone::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) +int CPitdrone::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { float flDist; Vector vecApex; @@ -899,13 +361,15 @@ int CPitDrone::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float } } + m_flLastHurtTime = gpGlobals->time; + return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType); } //========================================================= // CheckMeleeAttack1 - attack with both claws at the same time //========================================================= -BOOL CPitDrone::CheckMeleeAttack1(float flDot, float flDist) +BOOL CPitdrone::CheckMeleeAttack1(float flDot, float flDist) { // Give a better chance for MeleeAttack2 if (RANDOM_LONG(0,2) == 0) { @@ -917,9 +381,9 @@ BOOL CPitDrone::CheckMeleeAttack1(float flDot, float flDist) //========================================================= // CheckRangeAttack1 - spike attack //========================================================= -BOOL CPitDrone::CheckRangeAttack1(float flDot, float flDist) +BOOL CPitdrone::CheckRangeAttack1(float flDot, float flDist) { - if (spikes <= 0) + if (m_cAmmoLoaded <= 0) { return FALSE; } @@ -954,7 +418,7 @@ BOOL CPitDrone::CheckRangeAttack1(float flDot, float flDist) // SetYawSpeed - allows each sequence to have a different // turn rate associated with it. //========================================================= -void CPitDrone::SetYawSpeed(void) +void CPitdrone::SetYawSpeed(void) { int ys; @@ -979,7 +443,7 @@ void CPitDrone::SetYawSpeed(void) // of sounds this monster regards. In the base class implementation, // monsters care about all sounds, but no scents. //========================================================= -int CPitDrone::ISoundMask( void ) +int CPitdrone::ISoundMask( void ) { return bits_SOUND_WORLD | bits_SOUND_COMBAT | @@ -989,7 +453,7 @@ int CPitDrone::ISoundMask( void ) bits_SOUND_PLAYER; } -void CPitDrone::HandleAnimEvent(MonsterEvent_t *pEvent) +void CPitdrone::HandleAnimEvent(MonsterEvent_t *pEvent) { switch (pEvent->event) { @@ -1017,9 +481,8 @@ void CPitDrone::HandleAnimEvent(MonsterEvent_t *pEvent) // screeshake transforms the viewmodel as well as the viewangle. No problems with seeing the ends of the viewmodels. UTIL_ScreenShake( pHurt->pev->origin, 15.0, 1.5, 0.7, 2 ); - //In Opposing Force enemies just go up, but not forward - //pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100; - pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 300; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100; + pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_up * 200; } else EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG(0, ARRAYSIZE(pAttackMissSounds) - 1)], 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5, 5)); @@ -1050,22 +513,34 @@ void CPitDrone::HandleAnimEvent(MonsterEvent_t *pEvent) case PIT_DRONE_AE_RELOAD: { - spikes = PITDRONE_MAX_HORNS; - BodyChange(spikes); + if (m_iInitialAmmo >= 0) + m_cAmmoLoaded = PITDRONE_MAX_HORNS; + else + m_cAmmoLoaded = 0; + BodyChange(m_cAmmoLoaded); ClearConditions(bits_COND_NO_AMMO_LOADED); } break; case PIT_DRONE_AE_HOP: { + float flGravity = g_psv_gravity->value; + + // throw the squid up into the air on this frame. + if( FBitSet( pev->flags, FL_ONGROUND ) ) + { + pev->flags -= FL_ONGROUND; + } + // jump into air for 0.8 (24/30) seconds + pev->velocity.z += ( 0.625 * flGravity ) * 0.5; } break; case PIT_DRONE_AE_SPIT: { - spikes--; - BodyChange(spikes); + m_cAmmoLoaded--; + BodyChange(m_cAmmoLoaded); Vector vecSpitOffset; Vector vecSpitDir; @@ -1074,10 +549,15 @@ void CPitDrone::HandleAnimEvent(MonsterEvent_t *pEvent) // !!!HACKHACK - the spot at which the spit originates (in front of the mouth) was measured in 3ds and hardcoded here. // we should be able to read the position of bones at runtime for this info. - vecSpitOffset = (gpGlobals->v_right * 4 + gpGlobals->v_forward * 37 + gpGlobals->v_up * 40); + vecSpitOffset = (gpGlobals->v_forward * 15 + gpGlobals->v_up * 36); vecSpitOffset = (pev->origin + vecSpitOffset); //vecSpitDir = ((m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs) - vecSpitOffset).Normalize(); - vecSpitDir = (m_hEnemy->BodyTarget(pev->origin) - vecSpitOffset).Normalize(); + Vector vecEnemyPosition; + if (m_hEnemy != 0) + vecEnemyPosition = m_hEnemy->BodyTarget(pev->origin); + else + vecEnemyPosition = m_vecEnemyLKP; + vecSpitDir = (vecEnemyPosition - vecSpitOffset).Normalize(); vecSpitDir.x += RANDOM_FLOAT(-0.01, 0.01); vecSpitDir.y += RANDOM_FLOAT(-0.01, 0.01); @@ -1085,19 +565,18 @@ void CPitDrone::HandleAnimEvent(MonsterEvent_t *pEvent) // SOUND HERE! (in the pitdrone model) - CBaseEntity *pSpit = CBaseEntity::Create("pitdronespit", vecSpitOffset, UTIL_VecToAngles(vecSpitDir), edict()); - pSpit->pev->velocity = vecSpitDir * 900; + CPitdroneSpike::Shoot(pev, vecSpitOffset, vecSpitDir * 900, UTIL_VecToAngles(vecSpitDir)); // spew the spittle temporary ents. MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpitOffset ); WRITE_BYTE( TE_SPRITE_SPRAY ); WRITE_COORD( vecSpitOffset.x ); // pos - WRITE_COORD( vecSpitOffset.y ); - WRITE_COORD( vecSpitOffset.z ); + WRITE_COORD( vecSpitOffset.y ); + WRITE_COORD( vecSpitOffset.z ); WRITE_COORD( vecSpitDir.x ); // dir - WRITE_COORD( vecSpitDir.y ); - WRITE_COORD( vecSpitDir.z ); - WRITE_SHORT( iPitDroneSpitSprite ); // model + WRITE_COORD( vecSpitDir.y ); + WRITE_COORD( vecSpitDir.z ); + WRITE_SHORT( iPitdroneSpitSprite ); // model WRITE_BYTE( 15 ); // count WRITE_BYTE( 210 ); // speed WRITE_BYTE( 25 ); // noise ( client will divide by 100 ) @@ -1111,12 +590,12 @@ void CPitDrone::HandleAnimEvent(MonsterEvent_t *pEvent) } } -int CPitDrone::Classify(void) +int CPitdrone::Classify(void) { return CLASS_RACEX_PREDATOR; } -void CPitDrone::BodyChange(float horns) +void CPitdrone::BodyChange(float horns) { if (horns <= 0) SetBodygroup(HORNGROUP, PITDRONE_HORNS0); @@ -1151,7 +630,7 @@ void CPitDrone::BodyChange(float horns) //========================================================= // Spawn //========================================================= -void CPitDrone::Spawn() +void CPitdrone::Spawn() { Precache(); @@ -1168,38 +647,33 @@ void CPitDrone::Spawn() m_flNextSpitTime = gpGlobals->time; - BodyChange(spikes); - if (spikes) { - canReloadSpikes = TRUE; + if (m_iInitialAmmo >= 0) + { + m_cAmmoLoaded = Q_min(m_iInitialAmmo, PITDRONE_MAX_HORNS); +#if FEATURE_PITDRONE_SPAWN_WITH_SPIKES + if (!m_cAmmoLoaded) { + m_cAmmoLoaded = PITDRONE_MAX_HORNS; + } +#endif } + BodyChange(m_cAmmoLoaded); MonsterInit(); } //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CPitDrone::Precache() +void CPitdrone::Precache() { - int i; PRECACHE_MODEL("models/pit_drone.mdl"); PRECACHE_MODEL("models/pit_drone_gibs.mdl"); - PRECACHE_MODEL("models/pit_drone_spike.mdl");// spit projectile. - iPitDroneSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle. - - for (i = 0; i < ARRAYSIZE(pAttackMissSounds); i++) - PRECACHE_SOUND((char *)pAttackMissSounds[i]); - - for (i = 0; i < ARRAYSIZE(pIdleSounds); i++) - PRECACHE_SOUND((char *)pIdleSounds[i]); - - for (i = 0; i < ARRAYSIZE(pDieSounds); i++) - PRECACHE_SOUND((char *)pDieSounds[i]); + iPitdroneSpitSprite = PRECACHE_MODEL("sprites/tinyspit.spr");// client side spittle. - for (i = 0; i < ARRAYSIZE(pPainSounds); i++) - PRECACHE_SOUND((char *)pPainSounds[i]); - - for (i = 0; i < ARRAYSIZE(pAlertSounds); i++) - PRECACHE_SOUND((char *)pAlertSounds[i]); + PRECACHE_SOUND_ARRAY(pAttackMissSounds); + PRECACHE_SOUND_ARRAY(pIdleSounds); + PRECACHE_SOUND_ARRAY(pDieSounds); + PRECACHE_SOUND_ARRAY(pPainSounds); + PRECACHE_SOUND_ARRAY(pAlertSounds); PRECACHE_SOUND("bullchicken/bc_bite2.wav"); PRECACHE_SOUND("bullchicken/bc_bite3.wav"); @@ -1224,8 +698,7 @@ void CPitDrone::Precache() PRECACHE_SOUND("weapons/xbow_hitbod2.wav"); PRECACHE_SOUND("weapons/xbow_hit1.wav"); - UTIL_PrecacheOther("pitdronespit"); - + UTIL_PrecacheOther("pitdronespike"); } @@ -1233,7 +706,7 @@ void CPitDrone::Precache() // IdleSound //========================================================= #define PITDRONE_ATTN_IDLE (float)1.5 -void CPitDrone::IdleSound(void) +void CPitdrone::IdleSound(void) { EMIT_SOUND(ENT(pev), CHAN_VOICE, pIdleSounds[RANDOM_LONG(0, ARRAYSIZE(pIdleSounds)-1)], 1, PITDRONE_ATTN_IDLE); } @@ -1241,7 +714,7 @@ void CPitDrone::IdleSound(void) //========================================================= // PainSound //========================================================= -void CPitDrone::PainSound(void) +void CPitdrone::PainSound(void) { int iPitch = RANDOM_LONG(85, 120); EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, pPainSounds[RANDOM_LONG(0, ARRAYSIZE(pPainSounds)-1)], 1, ATTN_NORM, 0, iPitch); @@ -1250,7 +723,7 @@ void CPitDrone::PainSound(void) //========================================================= // AlertSound //========================================================= -void CPitDrone::AlertSound(void) +void CPitdrone::AlertSound(void) { int iPitch = RANDOM_LONG(140, 160); EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, pAlertSounds[RANDOM_LONG(0, ARRAYSIZE(pAlertSounds)-1)], 1, ATTN_NORM, 0, iPitch); @@ -1258,12 +731,12 @@ void CPitDrone::AlertSound(void) //========================================================= // DeathSound //========================================================= -void CPitDrone::DeathSound(void) +void CPitdrone::DeathSound(void) { EMIT_SOUND(ENT(pev), CHAN_VOICE, pDieSounds[RANDOM_LONG(0, ARRAYSIZE(pDieSounds)-1)], 1, ATTN_NORM); } -void CPitDrone::RunAI(void) +void CPitdrone::RunAI(void) { // first, do base class stuff CBaseMonster::RunAI(); @@ -1278,15 +751,15 @@ void CPitDrone::RunAI(void) } } -void CPitDrone::CheckAmmo( void ) +void CPitdrone::CheckAmmo( void ) { - if( spikes <= 0 ) + if( m_cAmmoLoaded <= 0 && m_iInitialAmmo >= 0 ) { SetConditions( bits_COND_NO_AMMO_LOADED ); } } -void CPitDrone::GibMonster() +void CPitdrone::GibMonster() { EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM ); @@ -1472,7 +945,7 @@ Schedule_t slPDroneHideReload[] = } }; -DEFINE_CUSTOM_SCHEDULES(CPitDrone) +DEFINE_CUSTOM_SCHEDULES(CPitdrone) { slPDroneRangeAttack1, slPDroneChaseEnemy, @@ -1482,12 +955,12 @@ DEFINE_CUSTOM_SCHEDULES(CPitDrone) slPDroneHideReload }; -IMPLEMENT_CUSTOM_SCHEDULES(CPitDrone, CBaseMonster) +IMPLEMENT_CUSTOM_SCHEDULES(CPitdrone, CBaseMonster) //========================================================= // GetSchedule //========================================================= -Schedule_t *CPitDrone::GetSchedule(void) +Schedule_t *CPitdrone::GetSchedule(void) { switch (m_MonsterState) { @@ -1546,7 +1019,7 @@ Schedule_t *CPitDrone::GetSchedule(void) return GetScheduleOfType(SCHED_PDRONE_EAT); } - if( HasConditions( bits_COND_NO_AMMO_LOADED ) && canReloadSpikes ) + if( HasConditions( bits_COND_NO_AMMO_LOADED ) && (m_iInitialAmmo >= 0) ) { return GetScheduleOfType( SCHED_PDRONE_COVER_AND_RELOAD ); } @@ -1578,7 +1051,7 @@ Schedule_t *CPitDrone::GetSchedule(void) //========================================================= // GetScheduleOfType //========================================================= -Schedule_t* CPitDrone::GetScheduleOfType(int Type) +Schedule_t* CPitdrone::GetScheduleOfType(int Type) { switch (Type) { @@ -1612,7 +1085,7 @@ Schedule_t* CPitDrone::GetScheduleOfType(int Type) // know explicitly when the last attempt to chase the enemy // failed, since that impacts its attack choices. //========================================================= -void CPitDrone::StartTask(Task_t *pTask) +void CPitdrone::StartTask(Task_t *pTask) { m_iTaskStatus = TASKSTATUS_RUNNING; @@ -1648,7 +1121,7 @@ void CPitDrone::StartTask(Task_t *pTask) //========================================================= // RunTask //========================================================= -void CPitDrone::RunTask(Task_t *pTask) +void CPitdrone::RunTask(Task_t *pTask) { switch( pTask->iTask ) { @@ -1670,4 +1143,3 @@ void CPitDrone::RunTask(Task_t *pTask) } } } -#endif